summaryrefslogtreecommitdiff
path: root/spec/requests/api
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests/api')
-rw-r--r--spec/requests/api/access_requests_spec.rb2
-rw-r--r--spec/requests/api/admin/batched_background_migrations_spec.rb2
-rw-r--r--spec/requests/api/admin/instance_clusters_spec.rb2
-rw-r--r--spec/requests/api/admin/plan_limits_spec.rb14
-rw-r--r--spec/requests/api/admin/sidekiq_spec.rb2
-rw-r--r--spec/requests/api/alert_management_alerts_spec.rb2
-rw-r--r--spec/requests/api/api_guard/admin_mode_middleware_spec.rb2
-rw-r--r--spec/requests/api/api_guard/response_coercer_middleware_spec.rb2
-rw-r--r--spec/requests/api/api_spec.rb2
-rw-r--r--spec/requests/api/appearance_spec.rb5
-rw-r--r--spec/requests/api/applications_spec.rb2
-rw-r--r--spec/requests/api/avatar_spec.rb2
-rw-r--r--spec/requests/api/award_emoji_spec.rb2
-rw-r--r--spec/requests/api/badges_spec.rb2
-rw-r--r--spec/requests/api/boards_spec.rb2
-rw-r--r--spec/requests/api/branches_spec.rb14
-rw-r--r--spec/requests/api/broadcast_messages_spec.rb2
-rw-r--r--spec/requests/api/bulk_imports_spec.rb5
-rw-r--r--spec/requests/api/ci/job_artifacts_spec.rb2
-rw-r--r--spec/requests/api/ci/jobs_spec.rb153
-rw-r--r--spec/requests/api/ci/pipeline_schedules_spec.rb2
-rw-r--r--spec/requests/api/ci/pipelines_spec.rb2
-rw-r--r--spec/requests/api/ci/resource_groups_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/jobs_artifacts_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/jobs_put_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb20
-rw-r--r--spec/requests/api/ci/runner/jobs_trace_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/runners_delete_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/runners_post_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/runners_reset_spec.rb2
-rw-r--r--spec/requests/api/ci/runner/runners_verify_post_spec.rb2
-rw-r--r--spec/requests/api/ci/runners_reset_registration_token_spec.rb2
-rw-r--r--spec/requests/api/ci/runners_spec.rb2
-rw-r--r--spec/requests/api/ci/secure_files_spec.rb19
-rw-r--r--spec/requests/api/ci/triggers_spec.rb2
-rw-r--r--spec/requests/api/ci/variables_spec.rb2
-rw-r--r--spec/requests/api/clusters/agent_tokens_spec.rb38
-rw-r--r--spec/requests/api/clusters/agents_spec.rb2
-rw-r--r--spec/requests/api/commit_statuses_spec.rb62
-rw-r--r--spec/requests/api/commits_spec.rb92
-rw-r--r--spec/requests/api/composer_packages_spec.rb23
-rw-r--r--spec/requests/api/conan_instance_packages_spec.rb4
-rw-r--r--spec/requests/api/conan_project_packages_spec.rb47
-rw-r--r--spec/requests/api/container_registry_event_spec.rb2
-rw-r--r--spec/requests/api/container_repositories_spec.rb9
-rw-r--r--spec/requests/api/debian_group_packages_spec.rb2
-rw-r--r--spec/requests/api/debian_project_packages_spec.rb2
-rw-r--r--spec/requests/api/dependency_proxy_spec.rb2
-rw-r--r--spec/requests/api/deploy_keys_spec.rb2
-rw-r--r--spec/requests/api/deploy_tokens_spec.rb12
-rw-r--r--spec/requests/api/deployments_spec.rb46
-rw-r--r--spec/requests/api/discussions_spec.rb69
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb2
-rw-r--r--spec/requests/api/environments_spec.rb6
-rw-r--r--spec/requests/api/error_tracking/client_keys_spec.rb2
-rw-r--r--spec/requests/api/error_tracking/collector_spec.rb2
-rw-r--r--spec/requests/api/error_tracking/project_settings_spec.rb2
-rw-r--r--spec/requests/api/events_spec.rb2
-rw-r--r--spec/requests/api/feature_flags_spec.rb2
-rw-r--r--spec/requests/api/feature_flags_user_lists_spec.rb2
-rw-r--r--spec/requests/api/features_spec.rb52
-rw-r--r--spec/requests/api/files_spec.rb171
-rw-r--r--spec/requests/api/freeze_periods_spec.rb2
-rw-r--r--spec/requests/api/generic_packages_spec.rb8
-rw-r--r--spec/requests/api/geo_spec.rb2
-rw-r--r--spec/requests/api/go_proxy_spec.rb2
-rw-r--r--spec/requests/api/graphql/boards/board_list_issues_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/boards/board_list_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/boards/board_lists_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/boards/boards_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/application_setting_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/ci_cd_setting_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/config_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/config_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/group_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/groups_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/instance_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/job_artifacts_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/job_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/jobs_spec.rb63
-rw-r--r--spec/requests/api/graphql/ci/manual_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/pipeline_schedules_spec.rb58
-rw-r--r--spec/requests/api/graphql/ci/pipelines_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/project_variables_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb264
-rw-r--r--spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/runners_spec.rb4
-rw-r--r--spec/requests/api/graphql/ci/stages_spec.rb2
-rw-r--r--spec/requests/api/graphql/ci/template_spec.rb2
-rw-r--r--spec/requests/api/graphql/container_repository/container_repository_details_spec.rb2
-rw-r--r--spec/requests/api/graphql/crm/contacts_spec.rb2
-rw-r--r--spec/requests/api/graphql/current_user/groups_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/current_user/todos_query_spec.rb4
-rw-r--r--spec/requests/api/graphql/current_user_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/current_user_todos_spec.rb3
-rw-r--r--spec/requests/api/graphql/custom_emoji_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/environments/deployments_spec.rb (renamed from spec/requests/api/graphql/environments/deployments_query_spec.rb)39
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/container_repositories_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/group_members_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/issues_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/labels_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/milestones_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/packages_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/timelogs_spec.rb2
-rw-r--r--spec/requests/api/graphql/group/work_item_types_spec.rb2
-rw-r--r--spec/requests/api/graphql/group_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/issue/issue_spec.rb2
-rw-r--r--spec/requests/api/graphql/issue_status_counts_spec.rb2
-rw-r--r--spec/requests/api/graphql/issues_spec.rb128
-rw-r--r--spec/requests/api/graphql/jobs_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/merge_request/merge_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/metadata_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb2
-rw-r--r--spec/requests/api/graphql/metrics/dashboard_query_spec.rb155
-rw-r--r--spec/requests/api/graphql/milestone_spec.rb2
-rw-r--r--spec/requests/api/graphql/multiplexed_queries_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/http_integration/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/http_integration/reset_token_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/http_integration/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/boards/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/boards/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/boards/lists/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/boards/lists/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/branches/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_artifact/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_play_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_retry_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_cancel_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule_create_spec.rb151
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule_delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb80
-rw-r--r--spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/clusters/agents/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/commits/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb21
-rw-r--r--spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/design_management/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/design_management/move_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/design_management/upload_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/groups/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb43
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb65
-rw-r--r--spec/requests/api/graphql/mutations/issues/move_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_locked_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_severity_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb89
-rw-r--r--spec/requests/api/graphql/mutations/issues/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/jira_import/start_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/labels/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb31
-rw-r--r--spec/requests/api/graphql/mutations/notes/destroy_spec.rb41
-rw-r--r--spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/note_spec.rb59
-rw-r--r--spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/packages/destroy_file_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/packages/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/release_asset_links/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/release_asset_links/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/releases/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/releases/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/releases/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/snippets/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/snippets/destroy_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb15
-rw-r--r--spec/requests/api/graphql/mutations/timelogs/create_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/timelogs/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/todos/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_done_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_many_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/uploads/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/user_callouts/create_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/user_preferences/update_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/work_items/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_spec.rb10
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_task_spec.rb2
-rw-r--r--spec/requests/api/graphql/namespace/package_settings_spec.rb2
-rw-r--r--spec/requests/api/graphql/namespace/projects_spec.rb2
-rw-r--r--spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb2
-rw-r--r--spec/requests/api/graphql/namespace_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/composer_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/conan_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/helm_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/maven_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/nuget_spec.rb2
-rw-r--r--spec/requests/api/graphql/packages/package_spec.rb13
-rw-r--r--spec/requests/api/graphql/packages/pypi_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert/metrics_dashboard_url_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert/notes_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/alert_management/alerts_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/alert_management/integrations_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/base_service_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/branch_rules_spec.rb81
-rw-r--r--spec/requests/api/graphql/project/cluster_agents_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/container_expiration_policy_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/container_repositories_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/deployment_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/environments_spec.rb133
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/fork_details_spec.rb60
-rw-r--r--spec/requests/api/graphql/project/fork_targets_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/grafana_integration_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/design_collection/version_spec.rb11
-rw-r--r--spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/designs/designs_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/designs/notes_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue/notes_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issue_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/issues_spec.rb698
-rw-r--r--spec/requests/api/graphql/project/jira_import_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/jira_projects_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/jira_service_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/job_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/jobs_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/labels_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/languages_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_request/pipelines_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_request_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/milestones_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/packages_cleanup_policy_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/packages_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/pipeline_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/project_members_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/project_statistics_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/release_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/releases_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/repository/blobs_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/repository_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/runners_spec.rb68
-rw-r--r--spec/requests/api/graphql/project/terraform/state_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/terraform/states_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/tree/tree_spec.rb50
-rw-r--r--spec/requests/api/graphql/project/work_item_types_spec.rb2
-rw-r--r--spec/requests/api/graphql/project/work_items_spec.rb134
-rw-r--r--spec/requests/api/graphql/project_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/query_spec.rb2
-rw-r--r--spec/requests/api/graphql/read_only_spec.rb2
-rw-r--r--spec/requests/api/graphql/snippets_spec.rb2
-rw-r--r--spec/requests/api/graphql/tasks/task_completion_status_spec.rb2
-rw-r--r--spec/requests/api/graphql/terraform/state/delete_spec.rb2
-rw-r--r--spec/requests/api/graphql/terraform/state/lock_spec.rb2
-rw-r--r--spec/requests/api/graphql/terraform/state/unlock_spec.rb2
-rw-r--r--spec/requests/api/graphql/todo_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/usage_trends_measurements_spec.rb2
-rw-r--r--spec/requests/api/graphql/user/group_member_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/user/project_member_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/user/starred_projects_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/user_query_spec.rb2
-rw-r--r--spec/requests/api/graphql/user_spec.rb2
-rw-r--r--spec/requests/api/graphql/users_spec.rb2
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb12
-rw-r--r--spec/requests/api/graphql_spec.rb6
-rw-r--r--spec/requests/api/group_avatar_spec.rb2
-rw-r--r--spec/requests/api/group_boards_spec.rb2
-rw-r--r--spec/requests/api/group_clusters_spec.rb2
-rw-r--r--spec/requests/api/group_container_repositories_spec.rb6
-rw-r--r--spec/requests/api/group_debian_distributions_spec.rb2
-rw-r--r--spec/requests/api/group_export_spec.rb2
-rw-r--r--spec/requests/api/group_import_spec.rb8
-rw-r--r--spec/requests/api/group_labels_spec.rb2
-rw-r--r--spec/requests/api/group_milestones_spec.rb2
-rw-r--r--spec/requests/api/group_packages_spec.rb2
-rw-r--r--spec/requests/api/group_variables_spec.rb2
-rw-r--r--spec/requests/api/groups_spec.rb2
-rw-r--r--spec/requests/api/helm_packages_spec.rb8
-rw-r--r--spec/requests/api/helpers_spec.rb2
-rw-r--r--spec/requests/api/import_bitbucket_server_spec.rb2
-rw-r--r--spec/requests/api/import_github_spec.rb2
-rw-r--r--spec/requests/api/integrations/jira_connect/subscriptions_spec.rb16
-rw-r--r--spec/requests/api/integrations_spec.rb2
-rw-r--r--spec/requests/api/internal/base_spec.rb48
-rw-r--r--spec/requests/api/internal/container_registry/migration_spec.rb2
-rw-r--r--spec/requests/api/internal/error_tracking_spec.rb2
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb18
-rw-r--r--spec/requests/api/internal/lfs_spec.rb2
-rw-r--r--spec/requests/api/internal/mail_room_spec.rb2
-rw-r--r--spec/requests/api/internal/pages_spec.rb2
-rw-r--r--spec/requests/api/internal/workhorse_spec.rb2
-rw-r--r--spec/requests/api/invitations_spec.rb2
-rw-r--r--spec/requests/api/issue_links_spec.rb6
-rw-r--r--spec/requests/api/issues/get_group_issues_spec.rb2
-rw-r--r--spec/requests/api/issues/get_project_issues_spec.rb2
-rw-r--r--spec/requests/api/issues/issues_spec.rb2
-rw-r--r--spec/requests/api/issues/post_projects_issues_spec.rb2
-rw-r--r--spec/requests/api/issues/put_projects_issues_spec.rb2
-rw-r--r--spec/requests/api/keys_spec.rb2
-rw-r--r--spec/requests/api/labels_spec.rb2
-rw-r--r--spec/requests/api/lint_spec.rb2
-rw-r--r--spec/requests/api/markdown_golden_master_spec.rb2
-rw-r--r--spec/requests/api/markdown_snapshot_spec.rb2
-rw-r--r--spec/requests/api/markdown_spec.rb2
-rw-r--r--spec/requests/api/maven_packages_spec.rb9
-rw-r--r--spec/requests/api/members_spec.rb2
-rw-r--r--spec/requests/api/merge_request_approvals_spec.rb83
-rw-r--r--spec/requests/api/merge_request_diffs_spec.rb2
-rw-r--r--spec/requests/api/merge_requests_spec.rb120
-rw-r--r--spec/requests/api/metadata_spec.rb2
-rw-r--r--spec/requests/api/metrics/dashboard/annotations_spec.rb2
-rw-r--r--spec/requests/api/metrics/user_starred_dashboards_spec.rb2
-rw-r--r--spec/requests/api/ml/mlflow_spec.rb135
-rw-r--r--spec/requests/api/namespaces_spec.rb2
-rw-r--r--spec/requests/api/notes_spec.rb47
-rw-r--r--spec/requests/api/notification_settings_spec.rb2
-rw-r--r--spec/requests/api/npm_instance_packages_spec.rb14
-rw-r--r--spec/requests/api/npm_project_packages_spec.rb17
-rw-r--r--spec/requests/api/nuget_group_packages_spec.rb6
-rw-r--r--spec/requests/api/nuget_project_packages_spec.rb56
-rw-r--r--spec/requests/api/oauth_tokens_spec.rb4
-rw-r--r--spec/requests/api/package_files_spec.rb2
-rw-r--r--spec/requests/api/pages/internal_access_spec.rb2
-rw-r--r--spec/requests/api/pages/pages_spec.rb2
-rw-r--r--spec/requests/api/pages/private_access_spec.rb2
-rw-r--r--spec/requests/api/pages/public_access_spec.rb2
-rw-r--r--spec/requests/api/pages_domains_spec.rb2
-rw-r--r--spec/requests/api/performance_bar_spec.rb3
-rw-r--r--spec/requests/api/personal_access_tokens/self_information_spec.rb2
-rw-r--r--spec/requests/api/personal_access_tokens_spec.rb2
-rw-r--r--spec/requests/api/project_attributes.yml6
-rw-r--r--spec/requests/api/project_clusters_spec.rb2
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb34
-rw-r--r--spec/requests/api/project_debian_distributions_spec.rb8
-rw-r--r--spec/requests/api/project_events_spec.rb2
-rw-r--r--spec/requests/api/project_export_spec.rb2
-rw-r--r--spec/requests/api/project_hooks_spec.rb2
-rw-r--r--spec/requests/api/project_import_spec.rb46
-rw-r--r--spec/requests/api/project_milestones_spec.rb2
-rw-r--r--spec/requests/api/project_packages_spec.rb12
-rw-r--r--spec/requests/api/project_repository_storage_moves_spec.rb2
-rw-r--r--spec/requests/api/project_snapshots_spec.rb4
-rw-r--r--spec/requests/api/project_snippets_spec.rb2
-rw-r--r--spec/requests/api/project_statistics_spec.rb2
-rw-r--r--spec/requests/api/project_templates_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb44
-rw-r--r--spec/requests/api/protected_branches_spec.rb2
-rw-r--r--spec/requests/api/protected_tags_spec.rb2
-rw-r--r--spec/requests/api/pypi_packages_spec.rb15
-rw-r--r--spec/requests/api/release/links_spec.rb2
-rw-r--r--spec/requests/api/releases_spec.rb2
-rw-r--r--spec/requests/api/remote_mirrors_spec.rb6
-rw-r--r--spec/requests/api/repositories_spec.rb10
-rw-r--r--spec/requests/api/resource_access_tokens_spec.rb2
-rw-r--r--spec/requests/api/resource_label_events_spec.rb2
-rw-r--r--spec/requests/api/resource_milestone_events_spec.rb2
-rw-r--r--spec/requests/api/rpm_project_packages_spec.rb22
-rw-r--r--spec/requests/api/rubygem_packages_spec.rb8
-rw-r--r--spec/requests/api/search_spec.rb2
-rw-r--r--spec/requests/api/settings_spec.rb16
-rw-r--r--spec/requests/api/sidekiq_metrics_spec.rb2
-rw-r--r--spec/requests/api/snippet_repository_storage_moves_spec.rb2
-rw-r--r--spec/requests/api/snippets_spec.rb2
-rw-r--r--spec/requests/api/statistics_spec.rb2
-rw-r--r--spec/requests/api/submodules_spec.rb2
-rw-r--r--spec/requests/api/suggestions_spec.rb2
-rw-r--r--spec/requests/api/system_hooks_spec.rb2
-rw-r--r--spec/requests/api/tags_spec.rb58
-rw-r--r--spec/requests/api/task_completion_status_spec.rb72
-rw-r--r--spec/requests/api/templates_spec.rb2
-rw-r--r--spec/requests/api/terraform/modules/v1/packages_spec.rb10
-rw-r--r--spec/requests/api/terraform/state_spec.rb321
-rw-r--r--spec/requests/api/terraform/state_version_spec.rb2
-rw-r--r--spec/requests/api/todos_spec.rb20
-rw-r--r--spec/requests/api/topics_spec.rb2
-rw-r--r--spec/requests/api/unleash_spec.rb81
-rw-r--r--spec/requests/api/usage_data_non_sql_metrics_spec.rb2
-rw-r--r--spec/requests/api/usage_data_queries_spec.rb4
-rw-r--r--spec/requests/api/usage_data_spec.rb2
-rw-r--r--spec/requests/api/user_counts_spec.rb2
-rw-r--r--spec/requests/api/users_preferences_spec.rb2
-rw-r--r--spec/requests/api/users_spec.rb25
-rw-r--r--spec/requests/api/v3/github_spec.rb2
-rw-r--r--spec/requests/api/wikis_spec.rb2
459 files changed, 3720 insertions, 1922 deletions
diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb
index 2af6c438fc9..8c14ead9e42 100644
--- a/spec/requests/api/access_requests_spec.rb
+++ b/spec/requests/api/access_requests_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::AccessRequests do
+RSpec.describe API::AccessRequests, feature_category: :authentication_and_authorization do
let_it_be(:maintainer) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:access_requester) { create(:user) }
diff --git a/spec/requests/api/admin/batched_background_migrations_spec.rb b/spec/requests/api/admin/batched_background_migrations_spec.rb
index 3b396a91d3e..9712777d261 100644
--- a/spec/requests/api/admin/batched_background_migrations_spec.rb
+++ b/spec/requests/api/admin/batched_background_migrations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Admin::BatchedBackgroundMigrations do
+RSpec.describe API::Admin::BatchedBackgroundMigrations, feature_category: :database do
let(:admin) { create(:admin) }
let(:unauthorized_user) { create(:user) }
diff --git a/spec/requests/api/admin/instance_clusters_spec.rb b/spec/requests/api/admin/instance_clusters_spec.rb
index 7b3224f58c5..7b510f74fd4 100644
--- a/spec/requests/api/admin/instance_clusters_spec.rb
+++ b/spec/requests/api/admin/instance_clusters_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::API::Admin::InstanceClusters do
+RSpec.describe ::API::Admin::InstanceClusters, feature_category: :kubernetes_management do
include KubernetesHelpers
let_it_be(:regular_user) { create(:user) }
diff --git a/spec/requests/api/admin/plan_limits_spec.rb b/spec/requests/api/admin/plan_limits_spec.rb
index 74ea3b0973f..2de7a66d803 100644
--- a/spec/requests/api/admin/plan_limits_spec.rb
+++ b/spec/requests/api/admin/plan_limits_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
+RSpec.describe API::Admin::PlanLimits, 'PlanLimits', feature_category: :not_owned do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be(:plan) { create(:plan, name: 'default') }
@@ -40,6 +40,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['pypi_max_file_size']).to eq(Plan.default.actual_limits.pypi_max_file_size)
expect(json_response['terraform_module_max_file_size']).to eq(Plan.default.actual_limits.terraform_module_max_file_size)
expect(json_response['storage_size_limit']).to eq(Plan.default.actual_limits.storage_size_limit)
+ expect(json_response['pipeline_hierarchy_size']).to eq(Plan.default.actual_limits.pipeline_hierarchy_size)
end
end
@@ -70,6 +71,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['pypi_max_file_size']).to eq(Plan.default.actual_limits.pypi_max_file_size)
expect(json_response['terraform_module_max_file_size']).to eq(Plan.default.actual_limits.terraform_module_max_file_size)
expect(json_response['storage_size_limit']).to eq(Plan.default.actual_limits.storage_size_limit)
+ expect(json_response['pipeline_hierarchy_size']).to eq(Plan.default.actual_limits.pipeline_hierarchy_size)
end
end
@@ -118,7 +120,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'nuget_max_file_size': 50,
'pypi_max_file_size': 60,
'terraform_module_max_file_size': 70,
- 'storage_size_limit': 80
+ 'storage_size_limit': 80,
+ 'pipeline_hierarchy_size': 250
}
expect(response).to have_gitlab_http_status(:ok)
@@ -140,6 +143,7 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
expect(json_response['pypi_max_file_size']).to eq(60)
expect(json_response['terraform_module_max_file_size']).to eq(70)
expect(json_response['storage_size_limit']).to eq(80)
+ expect(json_response['pipeline_hierarchy_size']).to eq(250)
end
it 'updates single plan limits' do
@@ -183,7 +187,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'nuget_max_file_size': 'e',
'pypi_max_file_size': 'f',
'terraform_module_max_file_size': 'g',
- 'storage_size_limit': 'j'
+ 'storage_size_limit': 'j',
+ 'pipeline_hierarchy_size': 'r'
}
expect(response).to have_gitlab_http_status(:bad_request)
@@ -204,7 +209,8 @@ RSpec.describe API::Admin::PlanLimits, 'PlanLimits' do
'nuget_max_file_size is invalid',
'pypi_max_file_size is invalid',
'terraform_module_max_file_size is invalid',
- 'storage_size_limit is invalid'
+ 'storage_size_limit is invalid',
+ 'pipeline_hierarchy_size is invalid'
)
end
end
diff --git a/spec/requests/api/admin/sidekiq_spec.rb b/spec/requests/api/admin/sidekiq_spec.rb
index 1e626c90e7e..0b456721d4f 100644
--- a/spec/requests/api/admin/sidekiq_spec.rb
+++ b/spec/requests/api/admin/sidekiq_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues do
+RSpec.describe API::Admin::Sidekiq, :clean_gitlab_redis_queues, feature_category: :not_owned do
let_it_be(:admin) { create(:admin) }
describe 'DELETE /admin/sidekiq/queues/:queue_name' do
diff --git a/spec/requests/api/alert_management_alerts_spec.rb b/spec/requests/api/alert_management_alerts_spec.rb
index 680a3883387..8dd0c46eab6 100644
--- a/spec/requests/api/alert_management_alerts_spec.rb
+++ b/spec/requests/api/alert_management_alerts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::AlertManagementAlerts do
+RSpec.describe API::AlertManagementAlerts, feature_category: :incident_management do
let_it_be(:creator) { create(:user) }
let_it_be(:project) do
create(:project, :public, creator_id: creator.id, namespace: creator.namespace)
diff --git a/spec/requests/api/api_guard/admin_mode_middleware_spec.rb b/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
index ba7a01a2cd9..21f3691c20b 100644
--- a/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
+++ b/spec/requests/api/api_guard/admin_mode_middleware_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::APIGuard::AdminModeMiddleware, :request_store do
+RSpec.describe API::APIGuard::AdminModeMiddleware, :request_store, feature_category: :not_owned do
let(:user) { create(:admin) }
it 'is loaded' do
diff --git a/spec/requests/api/api_guard/response_coercer_middleware_spec.rb b/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
index 6f3f97fe846..77498c2e2b3 100644
--- a/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
+++ b/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::APIGuard::ResponseCoercerMiddleware do
+RSpec.describe API::APIGuard::ResponseCoercerMiddleware, feature_category: :not_owned do
using RSpec::Parameterized::TableSyntax
it 'is loaded' do
diff --git a/spec/requests/api/api_spec.rb b/spec/requests/api/api_spec.rb
index 260f7cbc226..9cf9c313f11 100644
--- a/spec/requests/api/api_spec.rb
+++ b/spec/requests/api/api_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::API do
+RSpec.describe API::API, feature_category: :authentication_and_authorization do
include GroupAPIHelpers
describe 'Record user last activity in after hook' do
diff --git a/spec/requests/api/appearance_spec.rb b/spec/requests/api/appearance_spec.rb
index 69176e18d2e..84d5b091b8d 100644
--- a/spec/requests/api/appearance_spec.rb
+++ b/spec/requests/api/appearance_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Appearance, 'Appearance' do
+RSpec.describe API::Appearance, 'Appearance', feature_category: :navigation do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
@@ -33,6 +33,7 @@ RSpec.describe API::Appearance, 'Appearance' do
expect(json_response['new_project_guidelines']).to eq('')
expect(json_response['profile_image_guidelines']).to eq('')
expect(json_response['title']).to eq('')
+ expect(json_response['short_title']).to eq('')
end
end
end
@@ -51,6 +52,7 @@ RSpec.describe API::Appearance, 'Appearance' do
it "allows updating the settings" do
put api("/application/appearance", admin), params: {
title: "GitLab Test Instance",
+ short_title: "GitLab",
description: "gitlab-test.example.com",
new_project_guidelines: "Please read the FAQs for help.",
profile_image_guidelines: "Custom profile image guidelines"
@@ -70,6 +72,7 @@ RSpec.describe API::Appearance, 'Appearance' do
expect(json_response['new_project_guidelines']).to eq('Please read the FAQs for help.')
expect(json_response['profile_image_guidelines']).to eq('Custom profile image guidelines')
expect(json_response['title']).to eq('GitLab Test Instance')
+ expect(json_response['short_title']).to eq('GitLab')
end
end
diff --git a/spec/requests/api/applications_spec.rb b/spec/requests/api/applications_spec.rb
index 022451553ee..e238a1fb554 100644
--- a/spec/requests/api/applications_spec.rb
+++ b/spec/requests/api/applications_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Applications, :api do
+RSpec.describe API::Applications, :api, feature_category: :authentication_and_authorization do
let(:admin_user) { create(:user, admin: true) }
let(:user) { create(:user, admin: false) }
let(:scopes) { 'api' }
diff --git a/spec/requests/api/avatar_spec.rb b/spec/requests/api/avatar_spec.rb
index 656a086e550..8affbe6ec2b 100644
--- a/spec/requests/api/avatar_spec.rb
+++ b/spec/requests/api/avatar_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Avatar do
+RSpec.describe API::Avatar, feature_category: :users do
let(:gravatar_service) { double('GravatarService') }
describe 'GET /avatar' do
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index bb563f93bfe..87dc06b7d15 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::AwardEmoji do
+RSpec.describe API::AwardEmoji, feature_category: :not_owned do
let_it_be_with_reload(:project) { create(:project, :private) }
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb
index d8a345a79b0..6c6a7cc7cc6 100644
--- a/spec/requests/api/badges_spec.rb
+++ b/spec/requests/api/badges_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Badges do
+RSpec.describe API::Badges, feature_category: :projects do
let(:maintainer) { create(:user, username: 'maintainer_user') }
let(:developer) { create(:user) }
let(:access_requester) { create(:user) }
diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb
index 4d7256a1f03..69804c2c4a4 100644
--- a/spec/requests/api/boards_spec.rb
+++ b/spec/requests/api/boards_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Boards do
+RSpec.describe API::Boards, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:guest) { create(:user) }
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 750b9a39e15..eba1a06b5e4 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Branches do
+RSpec.describe API::Branches, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let(:project) { create(:project, :repository, creator: user, path: 'my.project', create_branch: 'ends-with.txt') }
@@ -344,6 +344,18 @@ RSpec.describe API::Branches do
end
end
+ context 'when branch is ambiguous' do
+ let(:branch_name) { 'prefix' }
+
+ before do
+ project.repository.create_branch('prefix/branch')
+ end
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(route, current_user) }
+ end
+ end
+
context 'when repository does not exist' do
it_behaves_like '404 response' do
let(:project) { create(:project, creator: user) }
diff --git a/spec/requests/api/broadcast_messages_spec.rb b/spec/requests/api/broadcast_messages_spec.rb
index 76412c80f4c..5cbb7dbfa12 100644
--- a/spec/requests/api/broadcast_messages_spec.rb
+++ b/spec/requests/api/broadcast_messages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::BroadcastMessages do
+RSpec.describe API::BroadcastMessages, feature_category: :onboarding do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be(:message) { create(:broadcast_message) }
diff --git a/spec/requests/api/bulk_imports_spec.rb b/spec/requests/api/bulk_imports_spec.rb
index ad57a370fc5..13f079c69e7 100644
--- a/spec/requests/api/bulk_imports_spec.rb
+++ b/spec/requests/api/bulk_imports_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::BulkImports do
+RSpec.describe API::BulkImports, feature_category: :importers do
let_it_be(:user) { create(:user) }
let_it_be(:import_1) { create(:bulk_import, user: user) }
let_it_be(:import_2) { create(:bulk_import, user: user) }
@@ -50,6 +50,9 @@ RSpec.describe API::BulkImports do
.to receive(:instance_version)
.and_return(
Gitlab::VersionInfo.new(::BulkImport::MIN_MAJOR_VERSION, ::BulkImport::MIN_MINOR_VERSION_FOR_PROJECT))
+ allow(instance)
+ .to receive(:instance_enterprise)
+ .and_return(false)
end
end
diff --git a/spec/requests/api/ci/job_artifacts_spec.rb b/spec/requests/api/ci/job_artifacts_spec.rb
index da9eb6b2216..a4a38179d11 100644
--- a/spec/requests/api/ci/job_artifacts_spec.rb
+++ b/spec/requests/api/ci/job_artifacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::JobArtifacts do
+RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do
include HttpBasicAuthHelpers
include DependencyProxyHelpers
diff --git a/spec/requests/api/ci/jobs_spec.rb b/spec/requests/api/ci/jobs_spec.rb
index c1b7461f444..4e348ae64b6 100644
--- a/spec/requests/api/ci/jobs_spec.rb
+++ b/spec/requests/api/ci/jobs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Jobs do
+RSpec.describe API::Ci::Jobs, feature_category: :continuous_integration do
include HttpBasicAuthHelpers
include DependencyProxyHelpers
@@ -190,15 +190,56 @@ RSpec.describe API::Ci::Jobs do
describe 'GET /job/allowed_agents' do
let_it_be(:group) { create(:group) }
- let_it_be(:group_agent) { create(:cluster_agent, project: create(:project, group: group)) }
- let_it_be(:group_authorization) { create(:agent_group_authorization, agent: group_agent, group: group) }
- let_it_be(:project_agent) { create(:cluster_agent, project: project) }
- before(:all) do
- project.update!(group: group_authorization.group)
+ # create a different project for the group agents to reference
+ # otherwise the AgentAuthorizationsFinder will pick up the project.cluster_agents' implicit authorizations
+ let_it_be(:other_project) { create(:project, group: group) }
+
+ let_it_be(:agent_authorizations_without_env) do
+ [
+ create(:agent_group_authorization, agent: create(:cluster_agent, project: other_project), group: group),
+ create(:agent_project_authorization, agent: create(:cluster_agent, project: project), project: project),
+ Clusters::Agents::ImplicitAuthorization.new(agent: create(:cluster_agent, project: project))
+ ]
+ end
+
+ let_it_be(:agent_authorizations_with_review_and_production_env) do
+ [
+ create(
+ :agent_group_authorization,
+ agent: create(:cluster_agent, project: other_project),
+ group: group,
+ environments: ['production', 'review/*']
+ ),
+ create(
+ :agent_project_authorization,
+ agent: create(:cluster_agent, project: project),
+ project: project,
+ environments: ['production', 'review/*']
+ )
+ ]
+ end
+
+ let_it_be(:agent_authorizations_with_staging_env) do
+ [
+ create(
+ :agent_group_authorization,
+ agent: create(:cluster_agent, project: other_project),
+ group: group,
+ environments: ['staging']
+ ),
+ create(
+ :agent_project_authorization,
+ agent: create(:cluster_agent, project: project),
+ project: project,
+ environments: ['staging']
+ )
+ ]
end
- let(:implicit_authorization) { Clusters::Agents::ImplicitAuthorization.new(agent: project_agent) }
+ before(:all) do
+ project.update!(group: group)
+ end
let(:headers) { { API::Ci::Helpers::Runner::JOB_TOKEN_HEADER => job.token } }
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user, status: job_status) }
@@ -215,30 +256,46 @@ RSpec.describe API::Ci::Jobs do
context 'when token is valid and user is authorized' do
shared_examples_for 'valid allowed_agents request' do
- it 'returns agent info', :aggregate_failures do
+ it 'returns the job info', :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.dig('job', 'id')).to eq(job.id)
expect(json_response.dig('pipeline', 'id')).to eq(job.pipeline_id)
expect(json_response.dig('project', 'id')).to eq(job.project_id)
- expect(json_response.dig('project', 'groups')).to match_array([{ 'id' => group_authorization.group.id }])
+ expect(json_response.dig('project', 'groups')).to match_array([{ 'id' => group.id }])
expect(json_response.dig('user', 'id')).to eq(api_user.id)
expect(json_response.dig('user', 'username')).to eq(api_user.username)
expect(json_response.dig('user', 'roles_in_project')).to match_array %w(guest reporter developer)
expect(json_response).not_to include('environment')
- expect(json_response['allowed_agents']).to match_array(
- [
- {
- 'id' => implicit_authorization.agent_id,
- 'config_project' => hash_including('id' => implicit_authorization.agent.project_id),
- 'configuration' => implicit_authorization.config
- },
- {
- 'id' => group_authorization.agent_id,
- 'config_project' => hash_including('id' => group_authorization.agent.project_id),
- 'configuration' => group_authorization.config
- }
- ])
+ end
+
+ it 'returns the agents allowed for the job' do
+ expected_allowed_agents = agent_authorizations_without_env.map do |agent_auth|
+ {
+ 'id' => agent_auth.agent_id,
+ 'config_project' => hash_including('id' => agent_auth.agent.project_id),
+ 'configuration' => agent_auth.config
+ }
+ end
+
+ expect(json_response['allowed_agents']).to match_array expected_allowed_agents
+ end
+ end
+
+ shared_examples_for 'valid allowed_agents request for a job with environment' do
+ it 'return the agents configured for the given environment' do
+ expected_allowed_agents = (
+ agent_authorizations_without_env +
+ agent_authorizations_with_review_and_production_env
+ ).map do |agent_auth|
+ {
+ 'id' => agent_auth.agent_id,
+ 'config_project' => hash_including('id' => agent_auth.agent.project_id),
+ 'configuration' => agent_auth.config
+ }
+ end
+
+ expect(json_response['allowed_agents']).to match_array(expected_allowed_agents)
end
end
@@ -254,21 +311,25 @@ RSpec.describe API::Ci::Jobs do
it 'includes environment tier' do
expect(json_response.dig('environment', 'tier')).to eq('production')
end
+
+ it_behaves_like 'valid allowed_agents request for a job with environment'
end
context 'when non-deployment environment action' do
let(:job) do
- create(:environment, name: 'review', project_id: project.id)
- create(:ci_build, :artifacts, :stop_review_app, environment: 'review', pipeline: pipeline, user: api_user, status: job_status)
+ create(:environment, name: 'review/123', project_id: project.id)
+ create(:ci_build, :artifacts, :stop_review_app, environment: 'review/123', pipeline: pipeline, user: api_user, status: job_status)
end
it 'includes environment slug' do
- expect(json_response.dig('environment', 'slug')).to eq('review')
+ expect(json_response.dig('environment', 'slug')).to match('review-123-.*')
end
it 'includes environment tier' do
expect(json_response.dig('environment', 'tier')).to eq('development')
end
+
+ it_behaves_like 'valid allowed_agents request for a job with environment'
end
context 'when passing the token as params' do
@@ -325,7 +386,7 @@ RSpec.describe API::Ci::Jobs do
context 'authorized user' do
it 'returns project jobs' do
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to include_pagination_headers
+ expect(response).to include_limited_pagination_headers
expect(json_response).to be_an Array
end
@@ -426,6 +487,46 @@ RSpec.describe API::Ci::Jobs do
end
end
+ describe 'GET /projects/:id/jobs rate limited' do
+ let(:query) { {} }
+
+ context 'with the ci_enforce_rate_limits_jobs_api feature flag on' do
+ before do
+ stub_feature_flags(ci_enforce_rate_limits_jobs_api: true)
+
+ allow_next_instance_of(Gitlab::ApplicationRateLimiter::BaseStrategy) do |strategy|
+ threshold = Gitlab::ApplicationRateLimiter.rate_limits[:jobs_index][:threshold]
+ allow(strategy).to receive(:increment).and_return(threshold + 1)
+ end
+
+ get api("/projects/#{project.id}/jobs", api_user), params: query
+ end
+
+ it 'enforces rate limits for the endpoint' do
+ expect(response).to have_gitlab_http_status :too_many_requests
+ expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
+ end
+ end
+
+ context 'with the ci_enforce_rate_limits_jobs_api feature flag off' do
+ before do
+ stub_feature_flags(ci_enforce_rate_limits_jobs_api: false)
+
+ allow_next_instance_of(Gitlab::ApplicationRateLimiter::BaseStrategy) do |strategy|
+ threshold = Gitlab::ApplicationRateLimiter.rate_limits[:jobs_index][:threshold]
+ allow(strategy).to receive(:increment).and_return(threshold + 1)
+ end
+
+ get api("/projects/#{project.id}/jobs", api_user), params: query
+ end
+
+ it 'makes a successful request' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_limited_pagination_headers
+ end
+ end
+ end
+
describe 'GET /projects/:id/jobs/:job_id' do
before do |example|
unless example.metadata[:skip_before_request]
diff --git a/spec/requests/api/ci/pipeline_schedules_spec.rb b/spec/requests/api/ci/pipeline_schedules_spec.rb
index 30badadde13..2a2c5f65aee 100644
--- a/spec/requests/api/ci/pipeline_schedules_spec.rb
+++ b/spec/requests/api/ci/pipeline_schedules_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::PipelineSchedules do
+RSpec.describe API::Ci::PipelineSchedules, feature_category: :continuous_integration do
let_it_be(:developer) { create(:user) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, public_builds: false) }
diff --git a/spec/requests/api/ci/pipelines_spec.rb b/spec/requests/api/ci/pipelines_spec.rb
index c9d06f37c8b..6d69da85449 100644
--- a/spec/requests/api/ci/pipelines_spec.rb
+++ b/spec/requests/api/ci/pipelines_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Pipelines do
+RSpec.describe API::Ci::Pipelines, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:project2) { create(:project, creator: user) }
diff --git a/spec/requests/api/ci/resource_groups_spec.rb b/spec/requests/api/ci/resource_groups_spec.rb
index 2a67a3e4322..26265aec1dc 100644
--- a/spec/requests/api/ci/resource_groups_spec.rb
+++ b/spec/requests/api/ci/resource_groups_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::ResourceGroups do
+RSpec.describe API::Ci::ResourceGroups, feature_category: :continuous_delivery do
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
index 9af0541bd2c..1c119079c50 100644
--- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/ci/runner/jobs_put_spec.rb b/spec/requests/api/ci/runner/jobs_put_spec.rb
index 8c95748aa5f..22817922b1b 100644
--- a/spec/requests/api/ci/runner/jobs_put_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_put_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
index d69a3f5a980..d15bc9d2dd5 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
@@ -175,6 +175,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
'allow_failure' => true }]
end
+ let(:expected_hooks) do
+ [{ 'name' => 'pre_get_sources_script', 'script' => ["echo 'hello pre_get_sources_script'"] }]
+ end
+
let(:expected_variables) do
[{ 'key' => 'CI_JOB_NAME', 'value' => 'spinach', 'public' => true, 'masked' => false },
{ 'key' => 'CI_JOB_STAGE', 'value' => 'test', 'public' => true, 'masked' => false },
@@ -230,6 +234,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
'variables' => [{ 'key' => 'MYSQL_ROOT_PASSWORD', 'value' => 'root123.' }], 'pull_policy' => nil }
])
expect(json_response['steps']).to eq(expected_steps)
+ expect(json_response['hooks']).to eq(expected_hooks)
expect(json_response['artifacts']).to eq(expected_artifacts)
expect(json_response['cache']).to match(expected_cache)
expect(json_response['variables']).to include(*expected_variables)
@@ -769,6 +774,19 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
end
end
+
+ context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
+ before do
+ stub_feature_flags(ci_hooks_pre_get_sources_script: false)
+ end
+
+ it 'does not return the pre_get_sources_script' do
+ request_job
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response).not_to have_key('hooks')
+ end
+ end
end
describe 'port support' do
diff --git a/spec/requests/api/ci/runner/jobs_trace_spec.rb b/spec/requests/api/ci/runner/jobs_trace_spec.rb
index d42043a7fe5..de67cec0a27 100644
--- a/spec/requests/api/ci/runner/jobs_trace_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_trace_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_trace_chunks, feature_category: :runner do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/ci/runner/runners_delete_spec.rb b/spec/requests/api/ci/runner/runners_delete_spec.rb
index 9d1bae7cce8..65c287a9535 100644
--- a/spec/requests/api/ci/runner/runners_delete_spec.rb
+++ b/spec/requests/api/ci/runner/runners_delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner_fleet do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/ci/runner/runners_post_spec.rb b/spec/requests/api/ci/runner/runners_post_spec.rb
index 47302046865..73f8e87a9fb 100644
--- a/spec/requests/api/ci/runner/runners_post_spec.rb
+++ b/spec/requests/api/ci/runner/runners_post_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner_fleet do
describe '/api/v4/runners' do
describe 'POST /api/v4/runners' do
context 'when no token is provided' do
diff --git a/spec/requests/api/ci/runner/runners_reset_spec.rb b/spec/requests/api/ci/runner/runners_reset_spec.rb
index 02b66a89a0a..6ab21138d26 100644
--- a/spec/requests/api/ci/runner/runners_reset_spec.rb
+++ b/spec/requests/api/ci/runner/runners_reset_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner_fleet do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/ci/runner/runners_verify_post_spec.rb b/spec/requests/api/ci/runner/runners_verify_post_spec.rb
index 038e126deaa..22a954cc444 100644
--- a/spec/requests/api/ci/runner/runners_verify_post_spec.rb
+++ b/spec/requests/api/ci/runner/runners_verify_post_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
+RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :runner do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/ci/runners_reset_registration_token_spec.rb b/spec/requests/api/ci/runners_reset_registration_token_spec.rb
index b8e4370fd46..1110dbf5fbc 100644
--- a/spec/requests/api/ci/runners_reset_registration_token_spec.rb
+++ b/spec/requests/api/ci/runners_reset_registration_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runners do
+RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
subject { post api("#{prefix}/runners/reset_registration_token", user) }
shared_examples 'bad request' do |result|
diff --git a/spec/requests/api/ci/runners_spec.rb b/spec/requests/api/ci/runners_spec.rb
index dd9894f2972..b07dd388390 100644
--- a/spec/requests/api/ci/runners_spec.rb
+++ b/spec/requests/api/ci/runners_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Runners do
+RSpec.describe API::Ci::Runners, feature_category: :runner_fleet do
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
diff --git a/spec/requests/api/ci/secure_files_spec.rb b/spec/requests/api/ci/secure_files_spec.rb
index b0bca6e9125..700fd97152a 100644
--- a/spec/requests/api/ci/secure_files_spec.rb
+++ b/spec/requests/api/ci/secure_files_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::SecureFiles do
+RSpec.describe API::Ci::SecureFiles, feature_category: :pipeline_authoring do
before do
stub_ci_secure_file_object_storage
stub_feature_flags(ci_secure_files: true)
@@ -31,23 +31,6 @@ RSpec.describe API::Ci::SecureFiles do
end
describe 'GET /projects/:id/secure_files' do
- context 'feature flag' do
- it 'returns a 503 when the feature flag is disabled' do
- stub_feature_flags(ci_secure_files: false)
-
- get api("/projects/#{project.id}/secure_files", maintainer)
-
- expect(response).to have_gitlab_http_status(:service_unavailable)
- end
-
- it 'returns a 200 when the feature flag is enabled' do
- get api("/projects/#{project.id}/secure_files", maintainer)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_a(Array)
- end
- end
-
context 'ci_secure_files_read_only feature flag' do
context 'when the flag is enabled' do
before do
diff --git a/spec/requests/api/ci/triggers_spec.rb b/spec/requests/api/ci/triggers_spec.rb
index f9b7880a4c4..ff54ba61309 100644
--- a/spec/requests/api/ci/triggers_spec.rb
+++ b/spec/requests/api/ci/triggers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Triggers do
+RSpec.describe API::Ci::Triggers, feature_category: :continuous_integration do
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
diff --git a/spec/requests/api/ci/variables_spec.rb b/spec/requests/api/ci/variables_spec.rb
index cafb841995d..c5d01afb7c4 100644
--- a/spec/requests/api/ci/variables_spec.rb
+++ b/spec/requests/api/ci/variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Ci::Variables do
+RSpec.describe API::Ci::Variables, feature_category: :pipeline_authoring do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, creator_id: user.id) }
diff --git a/spec/requests/api/clusters/agent_tokens_spec.rb b/spec/requests/api/clusters/agent_tokens_spec.rb
index a33bef53b14..b2d996e8002 100644
--- a/spec/requests/api/clusters/agent_tokens_spec.rb
+++ b/spec/requests/api/clusters/agent_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Clusters::AgentTokens do
+RSpec.describe API::Clusters::AgentTokens, feature_category: :kubernetes_management do
let_it_be(:agent) { create(:cluster_agent) }
let_it_be(:agent_token_one) { create(:cluster_agent_token, agent: agent) }
let_it_be(:revoked_agent_token) { create(:cluster_agent_token, :revoked, agent: agent) }
@@ -80,6 +80,27 @@ RSpec.describe API::Clusters::AgentTokens do
end
end
+ it 'returns an agent token that is revoked' do
+ get api("/projects/#{project.id}/cluster_agents/#{agent.id}/tokens/#{revoked_agent_token.id}", user)
+
+ aggregate_failures "testing response" do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/agent_token')
+ expect(json_response['id']).to eq(revoked_agent_token.id)
+ expect(json_response['name']).to eq(revoked_agent_token.name)
+ expect(json_response['agent_id']).to eq(agent.id)
+ expect(json_response['status']).to eq('revoked')
+ end
+ end
+
+ it 'returns a 404 if agent does not exist' do
+ path = "/projects/#{project.id}/cluster_agents/#{non_existing_record_id}/tokens/#{non_existing_record_id}"
+
+ get api(path, user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
it 'returns a 404 error if agent token id is not available' do
get api("/projects/#{project.id}/cluster_agents/#{agent.id}/tokens/#{non_existing_record_id}", user)
@@ -160,6 +181,21 @@ RSpec.describe API::Clusters::AgentTokens do
expect(agent_token_one.reload).to be_revoked
end
+ it 'returns a success response when revoking an already revoked agent token', :aggregate_failures do
+ delete api("/projects/#{project.id}/cluster_agents/#{agent.id}/tokens/#{revoked_agent_token.id}", user)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(revoked_agent_token.reload).to be_revoked
+ end
+
+ it 'returns a 404 error when given agent_id does not exist' do
+ path = "/projects/#{project.id}/cluster_agents/#{non_existing_record_id}/tokens/#{non_existing_record_id}"
+
+ delete api(path, user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
it 'returns a 404 error when revoking non existent agent token' do
delete api("/projects/#{project.id}/cluster_agents/#{agent.id}/tokens/#{non_existing_record_id}", user)
diff --git a/spec/requests/api/clusters/agents_spec.rb b/spec/requests/api/clusters/agents_spec.rb
index 5e3bdd69529..a09713bd6e7 100644
--- a/spec/requests/api/clusters/agents_spec.rb
+++ b/spec/requests/api/clusters/agents_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Clusters::Agents do
+RSpec.describe API::Clusters::Agents, feature_category: :kubernetes_management do
let_it_be(:agent) { create(:cluster_agent) }
let(:user) { agent.created_by_user }
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index dc5d9620dc4..025d065df7b 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::CommitStatuses do
+RSpec.describe API::CommitStatuses, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:commit) { project.repository.commit }
let_it_be(:guest) { create_user(:guest) }
@@ -167,7 +167,7 @@ RSpec.describe API::CommitStatuses do
let!(:pipeline) { create(:ci_pipeline, project: project, sha: sha, ref: 'ref') }
let(:params) { { state: 'pending' } }
- shared_examples_for 'creates a commit status for the existing pipeline' do
+ shared_examples_for 'creates a commit status for the existing pipeline with an external stage' do
it do
expect do
post api(post_url, developer), params: params
@@ -176,19 +176,73 @@ RSpec.describe API::CommitStatuses do
job = pipeline.statuses.find_by_name(json_response['name'])
expect(response).to have_gitlab_http_status(:created)
+ expect(job.ci_stage.name).to eq('external')
+ expect(job.ci_stage.position).to eq(GenericCommitStatus::EXTERNAL_STAGE_IDX)
+ expect(job.ci_stage.pipeline).to eq(pipeline)
expect(job.status).to eq('pending')
expect(job.stage_idx).to eq(GenericCommitStatus::EXTERNAL_STAGE_IDX)
end
end
- it_behaves_like 'creates a commit status for the existing pipeline'
+ shared_examples_for 'updates the commit status with an external stage' do
+ before do
+ post api(post_url, developer), params: { state: 'pending' }
+ end
+
+ it 'updates the commit status with the external stage' do
+ post api(post_url, developer), params: { state: 'running' }
+ job = pipeline.statuses.find_by_name(json_response['name'])
+
+ expect(job.ci_stage.name).to eq('external')
+ expect(job.ci_stage.position).to eq(GenericCommitStatus::EXTERNAL_STAGE_IDX)
+ expect(job.ci_stage.pipeline).to eq(pipeline)
+ expect(job.status).to eq('running')
+ expect(job.stage_idx).to eq(GenericCommitStatus::EXTERNAL_STAGE_IDX)
+ end
+ end
context 'with pipeline for merge request' do
let!(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline, source_project: project) }
let!(:pipeline) { merge_request.all_pipelines.last }
let(:sha) { pipeline.sha }
- it_behaves_like 'creates a commit status for the existing pipeline'
+ it_behaves_like 'creates a commit status for the existing pipeline with an external stage'
+ end
+
+ context 'when an external stage does not exist' do
+ context 'when the commit status does not exist' do
+ it_behaves_like 'creates a commit status for the existing pipeline with an external stage'
+ end
+
+ context 'when the commit status exists' do
+ it_behaves_like 'updates the commit status with an external stage'
+ end
+ end
+
+ context 'when an external stage already exists' do
+ let(:stage) { create(:ci_stage, name: 'external', pipeline: pipeline, position: 1_000_000) }
+
+ context 'when the commit status exists' do
+ it_behaves_like 'updates the commit status with an external stage'
+ end
+
+ context 'when the commit status does not exist' do
+ it_behaves_like 'creates a commit status for the existing pipeline with an external stage'
+ end
+ end
+ end
+
+ context 'when the pipeline does not exist' do
+ it 'creates a commit status and a stage' do
+ expect do
+ post api(post_url, developer), params: { state: 'pending' }
+ end.to change { Ci::Pipeline.count }.by(1)
+ job = Ci::Pipeline.last.statuses.find_by_name(json_response['name'])
+
+ expect(job.ci_stage.name).to eq('external')
+ expect(job.ci_stage.position).to eq(GenericCommitStatus::EXTERNAL_STAGE_IDX)
+ expect(job.status).to eq('pending')
+ expect(job.stage_idx).to eq(GenericCommitStatus::EXTERNAL_STAGE_IDX)
end
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 8a08d5203fd..5874d764b00 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'mime/types'
-RSpec.describe API::Commits do
+RSpec.describe API::Commits, feature_category: :source_code_management do
include ProjectForksHelper
include SessionHelpers
@@ -492,12 +492,32 @@ RSpec.describe API::Commits do
subject
end
- it_behaves_like 'Snowplow event tracking' do
- let(:namespace) { project.namespace }
- let(:category) { 'ide_edit' }
- let(:action) { 'g_edit_by_web_ide' }
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ let(:namespace) { project.namespace.reload }
+ let(:category) { 'Gitlab::UsageDataCounters::EditorUniqueCounter' }
+ let(:action) { 'ide_edit' }
+ let(:property) { 'g_edit_by_web_ide' }
+ let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
+ let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context] }
let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
+
+ context 'counts.web_ide_commits Snowplow event tracking' do
+ before do
+ allow(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_web_ide_edit_action)
+ end
+
+ it_behaves_like 'Snowplow event tracking' do
+ let(:action) { :commit }
+ let(:category) { described_class.to_s }
+ let(:namespace) { project.namespace.reload }
+ let(:label) { 'counts.web_ide_commits' }
+ let(:feature_flag_name) { 'route_hll_to_snowplow_phase3' }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis, key_path: 'counts.web_ide_commits').to_context.to_json]
+ end
+ end
+ end
end
context 'a new file in project repo' do
@@ -2206,7 +2226,7 @@ RSpec.describe API::Commits do
end
describe 'GET /projects/:id/repository/commits/:sha/signature' do
- let!(:project) { create(:project, :repository, :public) }
+ let_it_be(:project) { create(:project, :repository, :public) }
let(:project_id) { project.id }
let(:commit_id) { project.repository.commit.id }
let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}/signature" }
@@ -2228,7 +2248,7 @@ RSpec.describe API::Commits do
end
context 'gpg signed commit' do
- let(:commit) { project.repository.commit(GpgHelpers::SIGNED_COMMIT_SHA) }
+ let!(:commit) { project.commit(GpgHelpers::SIGNED_COMMIT_SHA) }
let(:commit_id) { commit.id }
it 'returns correct JSON' do
@@ -2244,8 +2264,8 @@ RSpec.describe API::Commits do
end
context 'x509 signed commit' do
- let(:commit) { project.repository.commit_by(oid: '189a6c924013fc3fe40d6f1ec1dc20214183bc97') }
- let(:commit_id) { commit.id }
+ let(:commit_id) { '189a6c924013fc3fe40d6f1ec1dc20214183bc97' }
+ let!(:commit) { project.commit(commit_id) }
it 'returns correct JSON' do
get api(route, current_user)
@@ -2276,5 +2296,59 @@ RSpec.describe API::Commits do
end
end
end
+
+ context 'with ssh signed commit' do
+ let(:commit_id) { '7b5160f9bb23a3d58a0accdbe89da13b96b1ece9' }
+ let!(:commit) { project.commit(commit_id) }
+
+ context 'when key belonging to author does not exist' do
+ it 'returns data without key' do
+ get api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['signature_type']).to eq('SSH')
+ expect(json_response['verification_status']).to eq(commit.signature.verification_status)
+ expect(json_response['key']).to be_nil
+ expect(json_response['commit_source']).to eq('gitaly')
+ end
+ end
+
+ context 'when key belonging to author exists' do
+ let(:user) { create(:user, email: commit.committer_email) }
+ let!(:key) { create(:key, user: user, key: extract_public_key_from_commit(commit), expires_at: 2.days.from_now) }
+
+ def extract_public_key_from_commit(commit)
+ ssh_commit = Gitlab::Ssh::Commit.new(commit)
+ signature_data = ::SSHData::Signature.parse_pem(ssh_commit.signature_text)
+ signature_data.public_key.openssh
+ end
+
+ it 'returns data including key' do
+ get api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['signature_type']).to eq('SSH')
+ expect(json_response['verification_status']).to eq(commit.signature.verification_status)
+ expect(json_response['key']['id']).to eq(key.id)
+ expect(json_response['key']['title']).to eq(key.title)
+ expect(json_response['key']['key']).to eq(key.publishable_key)
+ expect(Time.parse(json_response['key']['created_at'])).to be_like_time(key.created_at)
+ expect(Time.parse(json_response['key']['expires_at'])).to be_like_time(key.expires_at)
+ expect(json_response['commit_source']).to eq('gitaly')
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(ssh_commit_signatures: false)
+ end
+
+ it 'returns 404' do
+ get api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
end
diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb
index 53f3ef10743..0c726d46a01 100644
--- a/spec/requests/api/composer_packages_spec.rb
+++ b/spec/requests/api/composer_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::ComposerPackages do
+RSpec.describe API::ComposerPackages, feature_category: :package_registry do
include HttpBasicAuthHelpers
let_it_be(:user) { create(:user) }
@@ -14,7 +14,10 @@ RSpec.describe API::ComposerPackages do
let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
+ let(:snowplow_gitlab_standard_context) do
+ { project: project, namespace: project.namespace, user: user, property: 'i_package_composer_user' }
+ end
+
let(:headers) { {} }
using RSpec::Parameterized::TableSyntax
@@ -491,7 +494,6 @@ RSpec.describe API::ComposerPackages do
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
before do
project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
@@ -501,6 +503,10 @@ RSpec.describe API::ComposerPackages do
include_context 'Composer user type', params[:user_role], params[:member] do
if params[:expected_status] == :success
+ let(:snowplow_gitlab_standard_context) do
+ { project: project, namespace: project.namespace, property: 'i_package_composer_user' }
+ end
+
it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
else
it_behaves_like 'not a package tracking event'
@@ -509,6 +515,17 @@ RSpec.describe API::ComposerPackages do
end
it_behaves_like 'Composer publish with deploy tokens'
+
+ context 'with access to package registry for everyone' do
+ let(:headers) { {} }
+
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it_behaves_like 'returning response status', :success
+ end
end
end
diff --git a/spec/requests/api/conan_instance_packages_spec.rb b/spec/requests/api/conan_instance_packages_spec.rb
index b343e0cfc97..0c1d94560b5 100644
--- a/spec/requests/api/conan_instance_packages_spec.rb
+++ b/spec/requests/api/conan_instance_packages_spec.rb
@@ -2,8 +2,8 @@
require 'spec_helper'
-RSpec.describe API::ConanInstancePackages do
- let(:snowplow_standard_context_params) { { user: user, project: project, namespace: project.namespace } }
+RSpec.describe API::ConanInstancePackages, feature_category: :package_registry do
+ let(:snowplow_gitlab_standard_context) { { user: user, project: project, namespace: project.namespace, property: 'i_package_conan_user' } }
include_context 'conan api setup'
diff --git a/spec/requests/api/conan_project_packages_spec.rb b/spec/requests/api/conan_project_packages_spec.rb
index 4e6af9942ef..814745f9e29 100644
--- a/spec/requests/api/conan_project_packages_spec.rb
+++ b/spec/requests/api/conan_project_packages_spec.rb
@@ -1,11 +1,21 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::ConanProjectPackages do
+RSpec.describe API::ConanProjectPackages, feature_category: :package_registry do
include_context 'conan api setup'
let(:project_id) { project.id }
- let(:snowplow_standard_context_params) { { user: user, project: project, namespace: project.namespace } }
+
+ shared_examples 'accept get request on private project with access to package registry for everyone' do
+ subject { get api(url) }
+
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it_behaves_like 'returning response status', :ok
+ end
describe 'GET /api/v4/projects/:id/packages/conan/v1/ping' do
let(:url) { "/projects/#{project.id}/packages/conan/v1/ping" }
@@ -41,43 +51,50 @@ RSpec.describe API::ConanProjectPackages do
include_context 'conan recipe endpoints'
let(:url_prefix) { "#{Settings.gitlab.base_url}/api/v4/projects/#{project_id}" }
+ let(:recipe_path) { package.conan_recipe_path }
+
+ subject { get api(url), headers: headers }
describe 'GET /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel' do
- let(:recipe_path) { package.conan_recipe_path }
let(:url) { "/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}" }
it_behaves_like 'recipe snapshot endpoint'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference' do
- let(:recipe_path) { package.conan_recipe_path }
let(:url) { "/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}" }
it_behaves_like 'package snapshot endpoint'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/digest' do
- subject { get api("/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/digest"), headers: headers }
+ let(:url) { "/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/digest" }
it_behaves_like 'recipe download_urls endpoint'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference/download_urls' do
- subject { get api("/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}/download_urls"), headers: headers }
+ let(:url) { "/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}/download_urls" }
it_behaves_like 'package download_urls endpoint'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/download_urls' do
- subject { get api("/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/download_urls"), headers: headers }
+ let(:url) { "/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/download_urls" }
it_behaves_like 'recipe download_urls endpoint'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/packages/:conan_package_reference/digest' do
- subject { get api("/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}/digest"), headers: headers }
+ let(:url) { "/projects/#{project_id}/packages/conan/v1/conans/#{recipe_path}/packages/#{conan_package_reference}/digest" }
it_behaves_like 'package download_urls endpoint'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'POST /api/v4/projects/:id/packages/conan/v1/conans/:package_name/package_version/:package_username/:package_channel/upload_urls' do
@@ -102,24 +119,22 @@ RSpec.describe API::ConanProjectPackages do
context 'file download endpoints', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/326194' do
include_context 'conan file download endpoints'
+ subject { get api(url), headers: headers }
+
describe 'GET /api/v4/projects/:id/packages/conan/v1/files/:package_name/package_version/:package_username/:package_channel/:recipe_revision/export/:file_name' do
- subject do
- get api("/projects/#{project_id}/packages/conan/v1/files/#{recipe_path}/#{metadata.recipe_revision}/export/#{recipe_file.file_name}"),
- headers: headers
- end
+ let(:url) { "/projects/#{project_id}/packages/conan/v1/files/#{recipe_path}/#{metadata.recipe_revision}/export/#{recipe_file.file_name}" }
it_behaves_like 'recipe file download endpoint'
it_behaves_like 'project not found by project id'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/conan/v1/files/:package_name/package_version/:package_username/:package_channel/:recipe_revision/package/:conan_package_reference/:package_revision/:file_name' do
- subject do
- get api("/projects/#{project_id}/packages/conan/v1/files/#{recipe_path}/#{metadata.recipe_revision}/package/#{metadata.conan_package_reference}/#{metadata.package_revision}/#{package_file.file_name}"),
- headers: headers
- end
+ let(:url) { "/projects/#{project_id}/packages/conan/v1/files/#{recipe_path}/#{metadata.recipe_revision}/package/#{metadata.conan_package_reference}/#{metadata.package_revision}/#{package_file.file_name}" }
it_behaves_like 'package file download endpoint'
it_behaves_like 'project not found by project id'
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
end
diff --git a/spec/requests/api/container_registry_event_spec.rb b/spec/requests/api/container_registry_event_spec.rb
index 767e6e0b2ff..32c4b0e9598 100644
--- a/spec/requests/api/container_registry_event_spec.rb
+++ b/spec/requests/api/container_registry_event_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ContainerRegistryEvent do
+RSpec.describe API::ContainerRegistryEvent, feature_category: :container_registry do
let(:secret_token) { 'secret_token' }
let(:events) { [{ action: 'push' }] }
let(:registry_headers) { { 'Content-Type' => ::API::ContainerRegistryEvent::DOCKER_DISTRIBUTION_EVENTS_V1_JSON } }
diff --git a/spec/requests/api/container_repositories_spec.rb b/spec/requests/api/container_repositories_spec.rb
index 90f0243dbfc..4c1e52df4fc 100644
--- a/spec/requests/api/container_repositories_spec.rb
+++ b/spec/requests/api/container_repositories_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ContainerRepositories do
+RSpec.describe API::ContainerRepositories, feature_category: :container_registry do
include_context 'container registry client stubs'
let_it_be(:project) { create(:project, :private) }
@@ -75,6 +75,13 @@ RSpec.describe API::ContainerRepositories do
expect(json_response['id']).to eq(repository.id)
expect(response.body).to include('tags')
+ expect(json_response['tags']).to eq(repository.tags.map do |tag|
+ {
+ "location" => tag.location,
+ "name" => tag.name,
+ "path" => tag.path
+ }
+ end)
end
context 'with a network error' do
diff --git a/spec/requests/api/debian_group_packages_spec.rb b/spec/requests/api/debian_group_packages_spec.rb
index 9dbb75becf8..f4d5ef3fe90 100644
--- a/spec/requests/api/debian_group_packages_spec.rb
+++ b/spec/requests/api/debian_group_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::DebianGroupPackages do
+RSpec.describe API::DebianGroupPackages, feature_category: :package_registry do
include HttpBasicAuthHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/debian_project_packages_spec.rb b/spec/requests/api/debian_project_packages_spec.rb
index 6bef669cb3a..c27e165b39b 100644
--- a/spec/requests/api/debian_project_packages_spec.rb
+++ b/spec/requests/api/debian_project_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::DebianProjectPackages do
+RSpec.describe API::DebianProjectPackages, feature_category: :package_registry do
include HttpBasicAuthHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/dependency_proxy_spec.rb b/spec/requests/api/dependency_proxy_spec.rb
index 7af4ed08cb8..ef94cdbbe2b 100644
--- a/spec/requests/api/dependency_proxy_spec.rb
+++ b/spec/requests/api/dependency_proxy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::DependencyProxy, api: true do
+RSpec.describe API::DependencyProxy, api: true, feature_category: :dependency_proxy do
let_it_be(:user) { create(:user) }
let_it_be(:blob) { create(:dependency_proxy_blob) }
let_it_be(:group, reload: true) { blob.group }
diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb
index 1daa7c38e04..15880d920c5 100644
--- a/spec/requests/api/deploy_keys_spec.rb
+++ b/spec/requests/api/deploy_keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::DeployKeys do
+RSpec.describe API::DeployKeys, feature_category: :continuous_delivery do
let_it_be(:user) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/deploy_tokens_spec.rb b/spec/requests/api/deploy_tokens_spec.rb
index e0296248a03..4efe49e843f 100644
--- a/spec/requests/api/deploy_tokens_spec.rb
+++ b/spec/requests/api/deploy_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::DeployTokens do
+RSpec.describe API::DeployTokens, feature_category: :continuous_delivery do
let_it_be(:user) { create(:user) }
let_it_be(:creator) { create(:user) }
let_it_be(:project) { create(:project, creator_id: creator.id) }
@@ -346,7 +346,7 @@ RSpec.describe API::DeployTokens do
context 'deploy token creation' do
shared_examples 'creating a deploy token' do |entity, unauthenticated_response, authorized_role|
- let(:expires_time) { 1.year.from_now }
+ let(:expires_time) { 1.year.from_now.to_datetime }
let(:params) do
{
name: 'Foo',
@@ -414,6 +414,14 @@ RSpec.describe API::DeployTokens do
it { is_expected.to have_gitlab_http_status(:bad_request) }
end
+
+ context 'with an invalid expires_at date' do
+ before do
+ params[:expires_at] = 'foo'
+ end
+
+ it { is_expected.to have_gitlab_http_status(:bad_request) }
+ end
end
end
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index 8124080abea..efe76c9cfda 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Deployments do
+RSpec.describe API::Deployments, feature_category: :continuous_delivery do
let_it_be(:user) { create(:user) }
let_it_be(:non_member) { create(:user) }
@@ -16,8 +16,8 @@ RSpec.describe API::Deployments do
let_it_be(:staging) { create(:environment, :staging, project: project) }
let_it_be(:build) { create(:ci_build, :success, project: project) }
let_it_be(:deployment_1) { create(:deployment, :success, project: project, environment: production, deployable: build, ref: 'master', created_at: Time.now, updated_at: Time.now) }
- let_it_be(:deployment_2) { create(:deployment, :success, project: project, environment: staging, deployable: build, ref: 'master', created_at: 1.day.ago, updated_at: 2.hours.ago) }
- let_it_be(:deployment_3) { create(:deployment, :success, project: project, environment: staging, deployable: build, ref: 'master', created_at: 2.days.ago, updated_at: 1.hour.ago) }
+ let_it_be(:deployment_2) { create(:deployment, :success, project: project, environment: staging, deployable: build, ref: 'master', created_at: 1.day.ago, finished_at: 2.hours.ago, updated_at: 2.hours.ago) }
+ let_it_be(:deployment_3) { create(:deployment, :success, project: project, environment: staging, deployable: build, ref: 'master', created_at: 2.days.ago, finished_at: 1.hour.ago, updated_at: 1.hour.ago) }
def perform_request(params = {})
get api("/projects/#{project.id}/deployments", user), params: params
@@ -47,7 +47,7 @@ RSpec.describe API::Deployments do
end
context 'when forbidden order_by is specified' do
- it 'returns projects deployments with last update in specified datetime range' do
+ it 'returns an error' do
perform_request({ updated_before: 30.minutes.ago, updated_after: 90.minutes.ago, order_by: :id })
expect(response).to have_gitlab_http_status(:bad_request)
@@ -56,6 +56,44 @@ RSpec.describe API::Deployments do
end
end
+ context 'with finished after and before filters specified' do
+ context 'for successful deployments' do
+ it 'returns projects deployments finished before the specified datetime range' do
+ perform_request({ status: :success, finished_before: 90.minutes.ago, order_by: :finished_at, environment: 'staging' })
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.first['id']).to eq(deployment_2.id)
+ end
+
+ it 'returns projects deployments finished after the specified datetime range' do
+ perform_request({ status: :success, finished_after: 90.minutes.ago, order_by: :finished_at, environment: 'staging' })
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response.first['id']).to eq(deployment_3.id)
+ end
+ end
+
+ context 'for unsuccessful deployments' do
+ it 'returns an error' do
+ perform_request({ status: :failed, finished_before: 30.minutes.ago, order_by: :finished_at })
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to include('`finished_at` filter must be combined with `success` status filter.')
+ end
+ end
+
+ context 'when a forbidden order_by is specified' do
+ it 'returns an error' do
+ perform_request({ status: :success, finished_before: 30.minutes.ago, order_by: :id })
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to include('`finished_at` filter requires `finished_at` sort.')
+ end
+ end
+ end
+
context 'with the environment filter specifed' do
it 'returns deployments for the environment' do
perform_request({ environment: production.name })
diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb
index 258bd26c05a..38016375b8f 100644
--- a/spec/requests/api/discussions_spec.rb
+++ b/spec/requests/api/discussions_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Discussions do
+RSpec.describe API::Discussions, feature_category: :team_planning do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, :repository, namespace: user.namespace) }
let(:private_user) { create(:user) }
@@ -29,6 +29,73 @@ RSpec.describe API::Discussions do
end
end
+ context 'when noteable is a WorkItem' do
+ let!(:work_item) { create(:work_item, :issue, project: project, author: user) }
+ let!(:work_item_note) { create(:discussion_note_on_issue, noteable: work_item, project: project, author: user) }
+
+ let(:parent) { project }
+ let(:noteable) { work_item }
+ let(:note) { work_item_note }
+ let(:url) { "/projects/#{parent.id}/issues/#{noteable[:iid]}/discussions" }
+
+ it_behaves_like 'discussions API', 'projects', 'issues', 'iid', can_reply_to_individual_notes: true
+
+ context 'with work item without notes widget' do
+ before do
+ stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } })
+ stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] })
+ end
+
+ context 'when fetching discussions' do
+ it "returns 404" do
+ get api(url, user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when single fetching discussion by discussion_id' do
+ it "returns 404" do
+ get api("#{url}/#{work_item_note.discussion_id}", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when trying to create a new discussion' do
+ it "returns 404" do
+ post api(url, user), params: { body: 'hi!' }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when trying to create a new comment on a discussion' do
+ it 'returns 404' do
+ post api("#{url}/#{note.discussion_id}/notes", user), params: { body: 'Hello!' }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when trying to update a new comment on a discussion' do
+ it 'returns 404' do
+ put api("#{url}/notes/#{note.id}", user), params: { body: 'Update Hello!' }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when deleting a note' do
+ it 'returns 404' do
+ delete api("#{url}/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
context 'when noteable is a Snippet' do
let!(:snippet) { create(:project_snippet, project: project, author: user) }
let!(:snippet_note) { create(:discussion_note_on_project_snippet, noteable: snippet, project: project, author: user) }
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index 14da9a600cd..5116f074894 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'doorkeeper access' do
+RSpec.describe 'doorkeeper access', feature_category: :authentication_and_authorization do
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb
index a35c1630caa..d06e70a1a02 100644
--- a/spec/requests/api/environments_spec.rb
+++ b/spec/requests/api/environments_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Environments do
+RSpec.describe API::Environments, feature_category: :continuous_delivery do
let_it_be(:user) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:project) { create(:project, :private, :repository, namespace: user.namespace) }
@@ -321,8 +321,8 @@ RSpec.describe API::Environments do
expect(json_response["scheduled_entries"].size).to eq(1)
expect(json_response["scheduled_entries"].first["id"]).to eq(old_stopped_review_env.id)
expect(json_response["unprocessable_entries"].size).to eq(0)
- expect(json_response["scheduled_entries"]).to match_schema('public_api/v4/environments')
- expect(json_response["unprocessable_entries"]).to match_schema('public_api/v4/environments')
+ expect(json_response["scheduled_entries"]).to match_schema('public_api/v4/basic_environments')
+ expect(json_response["unprocessable_entries"]).to match_schema('public_api/v4/basic_environments')
expect(old_stopped_review_env.reload.auto_delete_at).to eq(1.week.from_now)
expect(new_stopped_review_env.reload.auto_delete_at).to be_nil
diff --git a/spec/requests/api/error_tracking/client_keys_spec.rb b/spec/requests/api/error_tracking/client_keys_spec.rb
index ba4d713dff2..cb840e1cffa 100644
--- a/spec/requests/api/error_tracking/client_keys_spec.rb
+++ b/spec/requests/api/error_tracking/client_keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ErrorTracking::ClientKeys do
+RSpec.describe API::ErrorTracking::ClientKeys, feature_category: :error_tracking do
let_it_be(:guest) { create(:user) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:setting) { create(:project_error_tracking_setting) }
diff --git a/spec/requests/api/error_tracking/collector_spec.rb b/spec/requests/api/error_tracking/collector_spec.rb
index dfca994d1c3..6a3e71bc859 100644
--- a/spec/requests/api/error_tracking/collector_spec.rb
+++ b/spec/requests/api/error_tracking/collector_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ErrorTracking::Collector do
+RSpec.describe API::ErrorTracking::Collector, feature_category: :error_tracking do
let_it_be(:project) { create(:project, :private) }
let_it_be(:setting) { create(:project_error_tracking_setting, :integrated, project: project) }
let_it_be(:client_key) { create(:error_tracking_client_key, project: project) }
diff --git a/spec/requests/api/error_tracking/project_settings_spec.rb b/spec/requests/api/error_tracking/project_settings_spec.rb
index c0c0680ef31..5906cdf105a 100644
--- a/spec/requests/api/error_tracking/project_settings_spec.rb
+++ b/spec/requests/api/error_tracking/project_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ErrorTracking::ProjectSettings do
+RSpec.describe API::ErrorTracking::ProjectSettings, feature_category: :error_tracking do
let_it_be(:user) { create(:user) }
let(:setting) { create(:project_error_tracking_setting) }
diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb
index d6c3999f22f..5c061a37ff3 100644
--- a/spec/requests/api/events_spec.rb
+++ b/spec/requests/api/events_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Events do
+RSpec.describe API::Events, feature_category: :users do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:private_project) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/feature_flags_spec.rb b/spec/requests/api/feature_flags_spec.rb
index bf7eec167f5..69e3633de57 100644
--- a/spec/requests/api/feature_flags_spec.rb
+++ b/spec/requests/api/feature_flags_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::FeatureFlags do
+RSpec.describe API::FeatureFlags, feature_category: :feature_flags do
include FeatureFlagHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/feature_flags_user_lists_spec.rb b/spec/requests/api/feature_flags_user_lists_spec.rb
index bfc57042ff4..443cbbea147 100644
--- a/spec/requests/api/feature_flags_user_lists_spec.rb
+++ b/spec/requests/api/feature_flags_user_lists_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::FeatureFlagsUserLists do
+RSpec.describe API::FeatureFlagsUserLists, feature_category: :feature_flags do
let_it_be(:project, refind: true) { create(:project) }
let_it_be(:client, refind: true) { create(:operations_feature_flags_client, project: project) }
let_it_be(:developer) { create(:user) }
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
index 85dafef569d..9f1af746080 100644
--- a/spec/requests/api/features_spec.rb
+++ b/spec/requests/api/features_spec.rb
@@ -2,8 +2,9 @@
require 'spec_helper'
-RSpec.describe API::Features, stub_feature_flags: false do
- let_it_be(:user) { create(:user) }
+RSpec.describe API::Features, stub_feature_flags: false, feature_category: :feature_flags do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:opted_out) { create(:user) }
let_it_be(:admin) { create(:admin) }
# Find any `development` feature flag name
@@ -35,7 +36,10 @@ RSpec.describe API::Features, stub_feature_flags: false do
{
'name' => 'feature_1',
'state' => 'on',
- 'gates' => [{ 'key' => 'boolean', 'value' => true }],
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => true },
+ { 'key' => 'actors', 'value' => ["#{opted_out.flipper_id}:opt_out"] }
+ ],
'definition' => nil
},
{
@@ -64,6 +68,7 @@ RSpec.describe API::Features, stub_feature_flags: false do
before do
Feature.enable('feature_1')
+ Feature.opt_out('feature_1', opted_out)
Feature.disable('feature_2')
Feature.enable('feature_3', Feature.group(:perf_team))
Feature.enable(known_feature_flag.name)
@@ -654,12 +659,53 @@ RSpec.describe API::Features, stub_feature_flags: false do
it_behaves_like 'sets the feature flag status'
+ it 'opts given actors out' do
+ Feature.enable(feature_name)
+ expect(Feature.enabled?(feature_name, user)).to be_truthy
+
+ post api("/features/#{feature_name}", admin), params: { value: 'opt_out', user: user.username }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response).to include(
+ 'name' => feature_name,
+ 'state' => 'on',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => true },
+ { 'key' => 'actors', 'value' => ["#{user.flipper_id}:opt_out"] }
+ ]
+ )
+ end
+
+ context 'when the actor has opted-out' do
+ before do
+ Feature.enable(feature_name)
+ Feature.opt_out(feature_name, user)
+ end
+
+ it 'refuses to enable the feature' do
+ post api("/features/#{feature_name}", admin), params: { value: 'true', user: user.username }
+
+ expect(Feature).not_to be_enabled(feature_name, user)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
context 'when feature flag set_feature_flag_service is disabled' do
before do
stub_feature_flags(set_feature_flag_service: false)
end
it_behaves_like 'sets the feature flag status'
+
+ it 'rejects opt_out requests' do
+ Feature.enable(feature_name)
+ expect(Feature).to be_enabled(feature_name, user)
+
+ post api("/features/#{feature_name}", admin), params: { value: 'opt_out', user: user.username }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
end
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index d4d3aace204..9cee3c06bb1 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Files do
+RSpec.describe API::Files, feature_category: :source_code_management do
include RepoHelpers
let_it_be(:group) { create(:group, :public) }
@@ -11,8 +11,12 @@ RSpec.describe API::Files do
let_it_be(:inherited_reporter) { create(:user) }
let_it_be(:inherited_developer) { create(:user) }
- let!(:project) { create(:project, :repository, namespace: user.namespace) }
- let(:guest) { create(:user) { |u| project.add_guest(u) } }
+ let_it_be_with_reload(:project) { create(:project, :repository, namespace: user.namespace) }
+ let_it_be_with_reload(:public_project) { create(:project, :public, :repository) }
+ let_it_be_with_reload(:private_project) { create(:project, :private, :repository, group: group) }
+ let_it_be_with_reload(:public_project_private_repo) { create(:project, :public, :repository, :repository_private, group: group) }
+
+ let_it_be(:guest) { create(:user) { |u| project.add_guest(u) } }
let(:file_path) { 'files%2Fruby%2Fpopen%2Erb' }
let(:file_name) { 'popen.rb' }
let(:last_commit_id) { '570e7b2abdd848b95f2f578043fc23bd6f6fd24d' }
@@ -183,8 +187,9 @@ RSpec.describe API::Files do
context 'when unauthenticated' do
context 'and project is public' do
+ let(:project) { public_project }
+
it_behaves_like 'repository files' do
- let(:project) { create(:project, :public, :repository) }
let(:current_user) { nil }
end
end
@@ -361,7 +366,7 @@ RSpec.describe API::Files do
context 'when unauthenticated' do
context 'and project is public' do
it_behaves_like 'repository files' do
- let(:project) { create(:project, :public, :repository) }
+ let(:project) { public_project }
let(:current_user) { nil }
let(:api_user) { nil }
end
@@ -406,7 +411,7 @@ RSpec.describe API::Files do
context 'when authenticated' do
context 'and user is an inherited member from the group' do
context 'when project is public with private repository' do
- let_it_be(:project) { create(:project, :public, :repository, :repository_private, group: group) }
+ let(:project) { public_project_private_repo }
context 'and user is a guest' do
it_behaves_like 'returns non-executable file attributes as json' do
@@ -428,7 +433,7 @@ RSpec.describe API::Files do
end
context 'when project is private' do
- let_it_be(:project) { create(:project, :private, :repository, group: group) }
+ let(:project) { private_project }
context 'and user is a guest' do
it_behaves_like '403 response' do
@@ -655,7 +660,7 @@ RSpec.describe API::Files do
context 'when unauthenticated' do
context 'and project is public' do
it_behaves_like 'repository blame files' do
- let(:project) { create(:project, :public, :repository) }
+ let(:project) { public_project }
let(:current_user) { nil }
end
end
@@ -774,12 +779,69 @@ RSpec.describe API::Files do
let(:request) { get api(route(file_path), current_user), params: params }
end
end
+
+ context 'when lfs parameter is true and the project has lfs enabled' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+ end
+
+ let(:request) { get api(route(file_path) + '/raw', current_user), params: params.merge(lfs: true) }
+ let(:file_path) { 'files%2Flfs%2Flfs_object.iso' }
+
+ it_behaves_like '404 response'
+
+ context 'and the file has an lfs object' do
+ let_it_be(:lfs_object) { create(:lfs_object, :with_file, oid: '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897') }
+
+ it_behaves_like '404 response'
+
+ context 'and the project has access to the lfs object' do
+ before do
+ project.lfs_objects << lfs_object
+ end
+
+ context 'and lfs uses local file storage' do
+ before do
+ Grape::Endpoint.before_each do |endpoint|
+ allow(endpoint).to receive(:sendfile).with(lfs_object.file.path)
+ end
+ end
+
+ after do
+ Grape::Endpoint.before_each nil
+ end
+
+ it 'responds with the lfs object file' do
+ request
+ expect(response.headers["Content-Disposition"]).to eq(
+ "attachment; filename=\"#{lfs_object.file.filename}\"; filename*=UTF-8''#{lfs_object.file.filename}"
+ )
+ end
+ end
+
+ context 'and lfs uses remote object storage' do
+ before do
+ stub_lfs_object_storage
+ lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE)
+ end
+
+ it 'redirects to the lfs object file' do
+ request
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response.location).to include(lfs_object.reload.file.path)
+ end
+ end
+ end
+ end
+ end
end
context 'when unauthenticated' do
context 'and project is public' do
it_behaves_like 'repository raw files' do
- let(:project) { create(:project, :public, :repository) }
+ let(:project) { public_project }
let(:current_user) { nil }
end
end
@@ -821,7 +883,7 @@ RSpec.describe API::Files do
end
describe 'POST /projects/:id/repository/files/:file_path' do
- let!(:file_path) { 'new_subfolder%2Fnewfile%2Erb' }
+ let(:file_path) { FFaker::Guid.guid }
let(:params) do
{
@@ -939,14 +1001,13 @@ RSpec.describe API::Files do
it_behaves_like 'creates a new file in the project repo' do
let(:current_user) { user }
- let(:file_path) { 'newfile%2Erb' }
+ let(:file_path) { FFaker::Guid.guid }
end
end
context 'when specifying an author' do
it 'creates a new file with the specified author' do
params.merge!(author_email: author_email, author_name: author_name)
-
post api(route('new_file_with_author%2Etxt'), user), params: params
expect(response).to have_gitlab_http_status(:created)
@@ -963,7 +1024,7 @@ RSpec.describe API::Files do
context 'when authenticated' do
context 'and user is an inherited member from the group' do
context 'when project is public with private repository' do
- let_it_be(:project) { create(:project, :public, :repository, :repository_private, group: group) }
+ let(:project) { public_project_private_repo }
context 'and user is a guest' do
it_behaves_like '403 response' do
@@ -985,7 +1046,7 @@ RSpec.describe API::Files do
end
context 'when project is private' do
- let_it_be(:project) { create(:project, :private, :repository, group: group) }
+ let(:project) { private_project }
context 'and user is a guest' do
it_behaves_like '403 response' do
@@ -1161,64 +1222,76 @@ RSpec.describe API::Files do
}
end
- it 'returns 400 when file path is invalid' do
- delete api(route(invalid_file_path), user), params: params
+ describe 'when files are deleted' do
+ let(:file_path) { FFaker::Guid.guid }
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['error']).to eq(invalid_file_message)
- end
+ before do
+ create_file_in_repo(project, 'master', 'master', file_path, 'Test file')
+ end
- it_behaves_like 'when path is absolute' do
- subject { delete api(route(absolute_path), user), params: params }
- end
+ it 'deletes existing file in project repo' do
+ delete api(route(file_path), user), params: params
- it 'deletes existing file in project repo' do
- delete api(route(file_path), user), params: params
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
- expect(response).to have_gitlab_http_status(:no_content)
- end
+ context 'when specifying an author' do
+ before do
+ params.merge!(author_email: author_email, author_name: author_name)
+ end
- context 'when no params given' do
- it 'returns a 400 bad request' do
- delete api(route(file_path), user)
+ it 'removes a file with the specified author' do
+ delete api(route(file_path), user), params: params
- expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
end
end
- context 'when the commit message is empty' do
- before do
- params[:commit_message] = ''
+ describe 'when files are not deleted' do
+ it_behaves_like 'when path is absolute' do
+ subject { delete api(route(absolute_path), user), params: params }
end
- it 'returns a 400 bad request' do
- delete api(route(file_path), user), params: params
+ it 'returns 400 when file path is invalid' do
+ delete api(route(invalid_file_path), user), params: params
expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq(invalid_file_message)
end
- end
- context 'when fails to delete file' do
- before do
- allow_next_instance_of(Repository) do |instance|
- allow(instance).to receive(:delete_file).and_raise(Gitlab::Git::CommitError, 'Cannot delete file')
+ context 'when no params given' do
+ it 'returns a 400 bad request' do
+ delete api(route(file_path), user)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
end
end
- it 'returns a 400 bad request' do
- delete api(route(file_path), user), params: params
+ context 'when the commit message is empty' do
+ before do
+ params[:commit_message] = ''
+ end
- expect(response).to have_gitlab_http_status(:bad_request)
+ it 'returns a 400 bad request' do
+ delete api(route(file_path), user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
- end
- context 'when specifying an author' do
- it 'removes a file with the specified author' do
- params.merge!(author_email: author_email, author_name: author_name)
+ context 'when fails to delete file' do
+ before do
+ allow_next_instance_of(Repository) do |instance|
+ allow(instance).to receive(:delete_file).and_raise(Gitlab::Git::CommitError, 'Cannot delete file')
+ end
+ end
- delete api(route(file_path), user), params: params
+ it 'returns a 400 bad request' do
+ delete api(route(file_path), user), params: params
- expect(response).to have_gitlab_http_status(:no_content)
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
end
end
end
diff --git a/spec/requests/api/freeze_periods_spec.rb b/spec/requests/api/freeze_periods_spec.rb
index 3da992301d5..170871706dc 100644
--- a/spec/requests/api/freeze_periods_spec.rb
+++ b/spec/requests/api/freeze_periods_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::FreezePeriods do
+RSpec.describe API::FreezePeriods, feature_category: :continuous_delivery do
let_it_be(:project) { create(:project, :repository, :private) }
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/generic_packages_spec.rb b/spec/requests/api/generic_packages_spec.rb
index 0478e123086..6b3f378a4bc 100644
--- a/spec/requests/api/generic_packages_spec.rb
+++ b/spec/requests/api/generic_packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GenericPackages do
+RSpec.describe API::GenericPackages, feature_category: :package_registry do
include HttpBasicAuthHelpers
using RSpec::Parameterized::TableSyntax
@@ -19,7 +19,7 @@ RSpec.describe API::GenericPackages do
let(:user) { personal_access_token.user }
let(:ci_build) { create(:ci_build, :running, user: user, project: project) }
- let(:snowplow_standard_context_params) { { user: user, project: project, namespace: project.namespace } }
+ let(:snowplow_gitlab_standard_context) { { user: user, project: project, namespace: project.namespace, property: 'i_package_generic_user' } }
def auth_header
return {} if user_role == :anonymous
@@ -408,8 +408,6 @@ RSpec.describe API::GenericPackages do
end
context 'event tracking' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
-
subject { upload_file(params, workhorse_headers.merge(personal_access_token_header)) }
it_behaves_like 'a package tracking event', described_class.name, 'push_package'
@@ -645,8 +643,6 @@ RSpec.describe API::GenericPackages do
end
context 'event tracking' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
-
before do
project.add_developer(user)
end
diff --git a/spec/requests/api/geo_spec.rb b/spec/requests/api/geo_spec.rb
index 4e77fa9405c..3dec91fd2fa 100644
--- a/spec/requests/api/geo_spec.rb
+++ b/spec/requests/api/geo_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Geo do
+RSpec.describe API::Geo, feature_category: :geo_replication do
include WorkhorseHelpers
describe 'GET /geo/proxy' do
diff --git a/spec/requests/api/go_proxy_spec.rb b/spec/requests/api/go_proxy_spec.rb
index 5498ed6df13..17189087ade 100644
--- a/spec/requests/api/go_proxy_spec.rb
+++ b/spec/requests/api/go_proxy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GoProxy do
+RSpec.describe API::GoProxy, feature_category: :package_registry do
include PackagesManagerApiSpecHelpers
include HttpBasicAuthHelpers
diff --git a/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb b/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
index 9bed720c815..2775c3d4c5a 100644
--- a/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'get board lists' do
+RSpec.describe 'get board lists', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/boards/board_list_query_spec.rb b/spec/requests/api/graphql/boards/board_list_query_spec.rb
index f01f7e87f10..b5ed0fe35d5 100644
--- a/spec/requests/api/graphql/boards/board_list_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_list_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Querying a Board list' do
+RSpec.describe 'Querying a Board list', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/boards/board_lists_query_spec.rb b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
index ad7df5c9344..2f23e93e2c6 100644
--- a/spec/requests/api/graphql/boards/board_lists_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'get board lists' do
+RSpec.describe 'get board lists', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/boards/boards_query_spec.rb b/spec/requests/api/graphql/boards/boards_query_spec.rb
index 50004e5a8a1..1407034fa5f 100644
--- a/spec/requests/api/graphql/boards/boards_query_spec.rb
+++ b/spec/requests/api/graphql/boards/boards_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'get list of boards' do
+RSpec.describe 'get list of boards', feature_category: :team_planning do
include GraphqlHelpers
include_context 'group and project boards query context'
diff --git a/spec/requests/api/graphql/ci/application_setting_spec.rb b/spec/requests/api/graphql/ci/application_setting_spec.rb
index 156ee550f16..42ab1786fee 100644
--- a/spec/requests/api/graphql/ci/application_setting_spec.rb
+++ b/spec/requests/api/graphql/ci/application_setting_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting Application Settings' do
+RSpec.describe 'getting Application Settings', feature_category: :continuous_integration do
include GraphqlHelpers
let(:fields) do
diff --git a/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb b/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
index 2dc7b9764fe..0437a30eccd 100644
--- a/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
+++ b/spec/requests/api/graphql/ci/ci_cd_setting_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Getting Ci Cd Setting' do
+RSpec.describe 'Getting Ci Cd Setting', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be_with_reload(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/ci/config_spec.rb b/spec/requests/api/graphql/ci/config_spec.rb
index 784019ee926..8154f132430 100644
--- a/spec/requests/api/graphql/ci/config_spec.rb
+++ b/spec/requests/api/graphql/ci/config_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.ciConfig' do
+RSpec.describe 'Query.ciConfig', feature_category: :continuous_integration do
include GraphqlHelpers
include StubRequests
diff --git a/spec/requests/api/graphql/ci/config_variables_spec.rb b/spec/requests/api/graphql/ci/config_variables_spec.rb
index 17133d7ea66..e6d73701b8f 100644
--- a/spec/requests/api/graphql/ci/config_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/config_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).ciConfigVariables(sha)' do
+RSpec.describe 'Query.project(fullPath).ciConfigVariables(sha)', feature_category: :pipeline_authoring do
include GraphqlHelpers
include ReactiveCachingHelpers
diff --git a/spec/requests/api/graphql/ci/group_variables_spec.rb b/spec/requests/api/graphql/ci/group_variables_spec.rb
index 7baf26c7648..51cbb4719f7 100644
--- a/spec/requests/api/graphql/ci/group_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.group(fullPath).ciVariables' do
+RSpec.describe 'Query.group(fullPath).ciVariables', feature_category: :pipeline_authoring do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/ci/groups_spec.rb b/spec/requests/api/graphql/ci/groups_spec.rb
index d1a4395d2c9..d1588833d8f 100644
--- a/spec/requests/api/graphql/ci/groups_spec.rb
+++ b/spec/requests/api/graphql/ci/groups_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Query.project.pipeline.stages.groups' do
+RSpec.describe 'Query.project.pipeline.stages.groups', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
diff --git a/spec/requests/api/graphql/ci/instance_variables_spec.rb b/spec/requests/api/graphql/ci/instance_variables_spec.rb
index cd6b2de98a1..e0397e17923 100644
--- a/spec/requests/api/graphql/ci/instance_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/instance_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.ciVariables' do
+RSpec.describe 'Query.ciVariables', feature_category: :pipeline_authoring do
include GraphqlHelpers
let(:query) do
diff --git a/spec/requests/api/graphql/ci/job_artifacts_spec.rb b/spec/requests/api/graphql/ci/job_artifacts_spec.rb
index df6e398fbe5..5fcb363d479 100644
--- a/spec/requests/api/graphql/ci/job_artifacts_spec.rb
+++ b/spec/requests/api/graphql/ci/job_artifacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).pipelines.jobs.artifacts' do
+RSpec.describe 'Query.project(fullPath).pipelines.jobs.artifacts', feature_category: :build do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
diff --git a/spec/requests/api/graphql/ci/job_spec.rb b/spec/requests/api/graphql/ci/job_spec.rb
index 3721155c71b..8121c5e5c85 100644
--- a/spec/requests/api/graphql/ci/job_spec.rb
+++ b/spec/requests/api/graphql/ci/job_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).pipelines.job(id)' do
+RSpec.describe 'Query.project(fullPath).pipelines.job(id)', feature_category: :continuous_integration do
include GraphqlHelpers
around do |example|
diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb
index a161c5c98ed..7a1dc614dcf 100644
--- a/spec/requests/api/graphql/ci/jobs_spec.rb
+++ b/spec/requests/api/graphql/ci/jobs_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Query.project.pipeline' do
+RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
@@ -367,4 +367,65 @@ RSpec.describe 'Query.project.pipeline' do
expect_graphql_errors_to_include [/"jobs" field can be requested only for 1 Project\(s\) at a time./]
end
end
+
+ context 'when batched querying jobs for multiple projects' do
+ let(:batched) do
+ [
+ { query: query_1 },
+ { query: query_2 }
+ ]
+ end
+
+ let(:query_1) do
+ %(
+ query Page1 {
+ projects {
+ nodes {
+ jobs {
+ nodes {
+ name
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:query_2) do
+ %(
+ query Page2 {
+ projects {
+ nodes {
+ jobs {
+ nodes {
+ name
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ before do
+ create_list(:project, 2).each do |project|
+ project.add_developer(user)
+ create(:ci_build, project: project)
+ end
+ end
+
+ it 'limits the specific field evaluation per query' do
+ get_multiplex(batched, current_user: user)
+
+ resp = json_response
+
+ expect(resp.first.dig('data', 'projects', 'nodes').first.dig('jobs', 'nodes').first['name']).to eq('test')
+ expect(resp.first['errors'].first['message'])
+ .to match(/"jobs" field can be requested only for 1 Project\(s\) at a time./)
+ expect(resp.second.dig('data', 'projects', 'nodes').first.dig('jobs', 'nodes').first['name']).to eq('test')
+ expect(resp.second['errors'].first['message'])
+ .to match(/"jobs" field can be requested only for 1 Project\(s\) at a time./)
+ end
+ end
end
diff --git a/spec/requests/api/graphql/ci/manual_variables_spec.rb b/spec/requests/api/graphql/ci/manual_variables_spec.rb
index a15bac2b8bd..921c69e535d 100644
--- a/spec/requests/api/graphql/ci/manual_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/manual_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).pipelines.jobs.manualVariables' do
+RSpec.describe 'Query.project(fullPath).pipelines.jobs.manualVariables', feature_category: :pipeline_authoring do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/ci/pipeline_schedules_spec.rb b/spec/requests/api/graphql/ci/pipeline_schedules_spec.rb
index 8b8ba09a95c..76adce6ff1b 100644
--- a/spec/requests/api/graphql/ci/pipeline_schedules_spec.rb
+++ b/spec/requests/api/graphql/ci/pipeline_schedules_spec.rb
@@ -2,11 +2,11 @@
require 'spec_helper'
-RSpec.describe 'Query.project.pipelineSchedules' do
+RSpec.describe 'Query.project.pipelineSchedules', feature_category: :continuous_integration do
include GraphqlHelpers
- let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, :public, creator: user, namespace: user.namespace) }
let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
let(:pipeline_schedule_graphql_data) { graphql_data_at(:project, :pipeline_schedules, :nodes, 0) }
@@ -29,6 +29,8 @@ RSpec.describe 'Query.project.pipelineSchedules' do
forTag
cron
cronTimezone
+ editPath
+ variables { nodes { #{all_graphql_fields_for('PipelineScheduleVariable')} } }
}
QUERY
end
@@ -61,6 +63,58 @@ RSpec.describe 'Query.project.pipelineSchedules' do
expect(pipeline_schedule_graphql_data['refPath']).to eq("/#{project.full_path}/-/commits/#{ref_for_display}")
expect(pipeline_schedule_graphql_data['forTag']).to be(false)
end
+
+ it 'returns the edit_path for a pipeline schedule' do
+ edit_path = pipeline_schedule_graphql_data['editPath']
+
+ expect(edit_path).to eq("/#{project.full_path}/-/pipeline_schedules/#{pipeline_schedule.id}/edit")
+ end
+ end
+
+ describe 'variables' do
+ let!(:env_vars) { create_list(:ci_pipeline_schedule_variable, 5, pipeline_schedule: pipeline_schedule) }
+
+ it 'returns all variables' do
+ post_graphql(query, current_user: user)
+
+ variables = pipeline_schedule_graphql_data['variables']['nodes']
+ expected = env_vars.map do |var|
+ a_graphql_entity_for(var, :key, :value, variable_type: var.variable_type.upcase)
+ end
+
+ expect(variables).to match_array(expected)
+ end
+
+ it 'is N+1 safe on the variables level' do
+ baseline = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: user) }
+
+ create_list(:ci_pipeline_schedule_variable, 2, pipeline_schedule: pipeline_schedule)
+
+ expect { post_graphql(query, current_user: user) }.not_to exceed_query_limit(baseline)
+ end
+
+ it 'is N+1 safe on the schedules level' do
+ baseline = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: user) }
+
+ pipeline_schedule_2 = create(:ci_pipeline_schedule, project: project, owner: user)
+ create_list(:ci_pipeline_schedule_variable, 2, pipeline_schedule: pipeline_schedule_2)
+
+ expect { post_graphql(query, current_user: user) }.not_to exceed_query_limit(baseline)
+ end
+ end
+
+ describe 'permissions' do
+ let_it_be(:another_user) { create(:user) }
+
+ before do
+ post_graphql(query, current_user: another_user)
+ end
+
+ it 'does not return the edit_path for a pipeline schedule for a user that does not have permissions' do
+ edit_path = pipeline_schedule_graphql_data['editPath']
+
+ expect(edit_path).to be nil
+ end
end
it 'avoids N+1 queries' do
diff --git a/spec/requests/api/graphql/ci/pipelines_spec.rb b/spec/requests/api/graphql/ci/pipelines_spec.rb
index 948704e8770..9fe71533b5e 100644
--- a/spec/requests/api/graphql/ci/pipelines_spec.rb
+++ b/spec/requests/api/graphql/ci/pipelines_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).pipelines' do
+RSpec.describe 'Query.project(fullPath).pipelines', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
diff --git a/spec/requests/api/graphql/ci/project_variables_spec.rb b/spec/requests/api/graphql/ci/project_variables_spec.rb
index d49a4a7e768..0338b58a0ea 100644
--- a/spec/requests/api/graphql/ci/project_variables_spec.rb
+++ b/spec/requests/api/graphql/ci/project_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).ciVariables' do
+RSpec.describe 'Query.project(fullPath).ciVariables', feature_category: :pipeline_authoring do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index 94c0a3c41bd..ca08e780758 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.runner(id)' do
+RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do
include GraphqlHelpers
let_it_be(:user) { create(:user, :admin) }
@@ -74,34 +74,39 @@ RSpec.describe 'Query.runner(id)' do
runner_data = graphql_data_at(:runner)
expect(runner_data).not_to be_nil
- expect(runner_data).to match a_hash_including(
- 'id' => runner.to_global_id.to_s,
- 'description' => runner.description,
- 'createdAt' => runner.created_at&.iso8601,
- 'contactedAt' => runner.contacted_at&.iso8601,
- 'version' => runner.version,
- 'shortSha' => runner.short_sha,
- 'revision' => runner.revision,
- 'locked' => false,
- 'active' => runner.active,
- 'paused' => !runner.active,
- 'status' => runner.status('14.5').to_s.upcase,
- 'maximumTimeout' => runner.maximum_timeout,
- 'accessLevel' => runner.access_level.to_s.upcase,
- 'runUntagged' => runner.run_untagged,
- 'ipAddress' => runner.ip_address,
- 'runnerType' => runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE',
- 'executorName' => runner.executor_type&.dasherize,
- 'architectureName' => runner.architecture,
- 'platformName' => runner.platform,
- 'maintenanceNote' => runner.maintenance_note,
- 'maintenanceNoteHtml' =>
+ expect(runner_data).to match a_graphql_entity_for(
+ runner,
+ description: runner.description,
+ created_at: runner.created_at&.iso8601,
+ contacted_at: runner.contacted_at&.iso8601,
+ version: runner.version,
+ short_sha: runner.short_sha,
+ revision: runner.revision,
+ locked: false,
+ active: runner.active,
+ paused: !runner.active,
+ status: runner.status('14.5').to_s.upcase,
+ job_execution_status: runner.builds.running.any? ? 'RUNNING' : 'IDLE',
+ maximum_timeout: runner.maximum_timeout,
+ access_level: runner.access_level.to_s.upcase,
+ run_untagged: runner.run_untagged,
+ ip_address: runner.ip_address,
+ runner_type: runner.instance_type? ? 'INSTANCE_TYPE' : 'PROJECT_TYPE',
+ executor_name: runner.executor_type&.dasherize,
+ architecture_name: runner.architecture,
+ platform_name: runner.platform,
+ maintenance_note: runner.maintenance_note,
+ maintenance_note_html:
runner.maintainer_note.present? ? a_string_including('<strong>Test maintenance note</strong>') : '',
- 'jobCount' => 0,
- 'jobs' => a_hash_including("count" => 0, "nodes" => [], "pageInfo" => anything),
- 'projectCount' => nil,
- 'adminUrl' => "http://localhost/admin/runners/#{runner.id}",
- 'userPermissions' => {
+ job_count: runner.builds.count,
+ jobs: a_hash_including(
+ "count" => runner.builds.count,
+ "nodes" => an_instance_of(Array),
+ "pageInfo" => anything
+ ),
+ project_count: nil,
+ admin_url: "http://localhost/admin/runners/#{runner.id}",
+ user_permissions: {
'readRunner' => true,
'updateRunner' => true,
'deleteRunner' => true,
@@ -129,10 +134,7 @@ RSpec.describe 'Query.runner(id)' do
runner_data = graphql_data_at(:runner)
expect(runner_data).not_to be_nil
- expect(runner_data).to match a_hash_including(
- 'id' => runner.to_global_id.to_s,
- 'adminUrl' => nil
- )
+ expect(runner_data).to match a_graphql_entity_for(runner, admin_url: nil)
expect(runner_data['tagList']).to match_array runner.tag_list
end
end
@@ -179,6 +181,16 @@ RSpec.describe 'Query.runner(id)' do
expect(runner_data).not_to include('tagList')
end
end
+
+ context 'with build running' do
+ before do
+ project = create(:project, :repository)
+ pipeline = create(:ci_pipeline, project: project)
+ create(:ci_build, :running, runner: runner, pipeline: pipeline)
+ end
+
+ it_behaves_like 'runner details fetch'
+ end
end
describe 'for project runner' do
@@ -216,9 +228,47 @@ RSpec.describe 'Query.runner(id)' do
runner_data = graphql_data_at(:runner)
- expect(runner_data).to match a_hash_including(
- 'id' => project_runner.to_global_id.to_s,
- 'locked' => is_locked
+ expect(runner_data).to match a_graphql_entity_for(project_runner, locked: is_locked)
+ end
+ end
+ end
+
+ describe 'jobCount' do
+ let_it_be(:pipeline1) { create(:ci_pipeline, project: project1) }
+ let_it_be(:pipeline2) { create(:ci_pipeline, project: project1) }
+ let_it_be(:build1) { create(:ci_build, :running, runner: active_project_runner, pipeline: pipeline1) }
+ let_it_be(:build2) { create(:ci_build, :running, runner: active_project_runner, pipeline: pipeline2) }
+
+ let(:runner_query_fragment) { 'id jobCount' }
+ let(:query) do
+ %(
+ query {
+ runner1: runner(id: "#{active_project_runner.to_global_id}") { #{runner_query_fragment} }
+ runner2: runner(id: "#{inactive_instance_runner.to_global_id}") { #{runner_query_fragment} }
+ }
+ )
+ end
+
+ it 'retrieves correct jobCount values' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data).to match a_hash_including(
+ 'runner1' => a_graphql_entity_for(active_project_runner, job_count: 2),
+ 'runner2' => a_graphql_entity_for(inactive_instance_runner, job_count: 0)
+ )
+ end
+
+ context 'when JOB_COUNT_LIMIT is in effect' do
+ before do
+ stub_const('Types::Ci::RunnerType::JOB_COUNT_LIMIT', 0)
+ end
+
+ it 'retrieves correct capped jobCount values' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data).to match a_hash_including(
+ 'runner1' => a_graphql_entity_for(active_project_runner, job_count: 1),
+ 'runner2' => a_graphql_entity_for(inactive_instance_runner, job_count: 0)
)
end
end
@@ -243,18 +293,8 @@ RSpec.describe 'Query.runner(id)' do
post_graphql(query, current_user: user)
expect(graphql_data).to match a_hash_including(
- 'runner1' => {
- 'id' => runner1.to_global_id.to_s,
- 'ownerProject' => {
- 'id' => project2.to_global_id.to_s
- }
- },
- 'runner2' => {
- 'id' => runner2.to_global_id.to_s,
- 'ownerProject' => {
- 'id' => project1.to_global_id.to_s
- }
- }
+ 'runner1' => a_graphql_entity_for(runner1, owner_project: a_graphql_entity_for(project2)),
+ 'runner2' => a_graphql_entity_for(runner2, owner_project: a_graphql_entity_for(project1))
)
end
end
@@ -284,8 +324,8 @@ RSpec.describe 'Query.runner(id)' do
it 'retrieves groups field with expected value' do
post_graphql(query, current_user: user)
- runner_data = graphql_data_at(:runner, :groups)
- expect(runner_data).to eq 'nodes' => [{ 'id' => group.to_global_id.to_s }]
+ runner_data = graphql_data_at(:runner, :groups, :nodes)
+ expect(runner_data).to contain_exactly(a_graphql_entity_for(group))
end
end
@@ -409,13 +449,13 @@ RSpec.describe 'Query.runner(id)' do
'jobCount' => 1,
'jobs' => a_hash_including(
"count" => 1,
- "nodes" => [{ "id" => job.to_global_id.to_s, "status" => job.status.upcase }]
+ "nodes" => [a_graphql_entity_for(job, status: job.status.upcase)]
),
'projectCount' => 2,
'projects' => {
'nodes' => [
- { 'id' => project1.to_global_id.to_s },
- { 'id' => project2.to_global_id.to_s }
+ a_graphql_entity_for(project1),
+ a_graphql_entity_for(project2)
]
})
expect(runner2_data).to match a_hash_including(
@@ -486,15 +526,24 @@ RSpec.describe 'Query.runner(id)' do
groups {
nodes {
id
+ path
+ fullPath
+ webUrl
}
}
projects {
nodes {
id
+ path
+ fullPath
+ webUrl
}
}
ownerProject {
id
+ path
+ fullPath
+ webUrl
}
}
SINGLE
@@ -503,8 +552,8 @@ RSpec.describe 'Query.runner(id)' do
let(:active_project_runner2) { create(:ci_runner, :project) }
let(:active_group_runner2) { create(:ci_runner, :group) }
- # Currently excluding known N+1 issues, see https://gitlab.com/gitlab-org/gitlab/-/issues/334759
- let(:excluded_fields) { %w[jobCount groups projects ownerProject] }
+ # Exclude fields that are already hardcoded above
+ let(:excluded_fields) { %w[jobs groups projects ownerProject] }
let(:single_query) do
<<~QUERY
@@ -542,27 +591,98 @@ RSpec.describe 'Query.runner(id)' do
expect(graphql_data.count).to eq 6
expect(graphql_data).to match(
a_hash_including(
- 'instance_runner1' => a_hash_including('id' => active_instance_runner.to_global_id.to_s),
- 'instance_runner2' => a_hash_including('id' => inactive_instance_runner.to_global_id.to_s),
- 'group_runner1' => a_hash_including(
- 'id' => active_group_runner.to_global_id.to_s,
- 'groups' => { 'nodes' => [a_hash_including('id' => group.to_global_id.to_s)] }
+ 'instance_runner1' => a_graphql_entity_for(active_instance_runner),
+ 'instance_runner2' => a_graphql_entity_for(inactive_instance_runner),
+ 'group_runner1' => a_graphql_entity_for(
+ active_group_runner,
+ groups: { 'nodes' => contain_exactly(a_graphql_entity_for(group)) }
),
- 'group_runner2' => a_hash_including(
- 'id' => active_group_runner2.to_global_id.to_s,
- 'groups' => { 'nodes' => [a_hash_including('id' => active_group_runner2.groups[0].to_global_id.to_s)] }
+ 'group_runner2' => a_graphql_entity_for(
+ active_group_runner2,
+ groups: { 'nodes' => active_group_runner2.groups.map { |g| a_graphql_entity_for(g) } }
),
- 'project_runner1' => a_hash_including(
- 'id' => active_project_runner.to_global_id.to_s,
- 'projects' => { 'nodes' => [a_hash_including('id' => active_project_runner.projects[0].to_global_id.to_s)] },
- 'ownerProject' => a_hash_including('id' => active_project_runner.projects[0].to_global_id.to_s)
+ 'project_runner1' => a_graphql_entity_for(
+ active_project_runner,
+ projects: { 'nodes' => active_project_runner.projects.map { |p| a_graphql_entity_for(p) } },
+ owner_project: a_graphql_entity_for(active_project_runner.projects[0])
),
- 'project_runner2' => a_hash_including(
- 'id' => active_project_runner2.to_global_id.to_s,
- 'projects' => {
- 'nodes' => [a_hash_including('id' => active_project_runner2.projects[0].to_global_id.to_s)]
- },
- 'ownerProject' => a_hash_including('id' => active_project_runner2.projects[0].to_global_id.to_s)
+ 'project_runner2' => a_graphql_entity_for(
+ active_project_runner2,
+ projects: { 'nodes' => active_project_runner2.projects.map { |p| a_graphql_entity_for(p) } },
+ owner_project: a_graphql_entity_for(active_project_runner2.projects[0])
+ )
+ ))
+ end
+ end
+
+ describe 'Query limits with jobs' do
+ let!(:group1) { create(:group) }
+ let!(:group2) { create(:group) }
+ let!(:project1) { create(:project, :repository, group: group1) }
+ let!(:project2) { create(:project, :repository, group: group1) }
+ let!(:project3) { create(:project, :repository, group: group2) }
+
+ let!(:merge_request1) { create(:merge_request, source_project: project1) }
+ let!(:merge_request2) { create(:merge_request, source_project: project3) }
+
+ let(:project_runner2) { create(:ci_runner, :project, projects: [project1, project2]) }
+ let!(:build1) { create(:ci_build, :success, name: 'Build One', runner: project_runner2, pipeline: pipeline1) }
+ let!(:pipeline1) do
+ create(:ci_pipeline, project: project1, source: :merge_request_event, merge_request: merge_request1, ref: 'main',
+ target_sha: 'xxx')
+ end
+
+ let(:query) do
+ <<~QUERY
+ {
+ runner(id: "#{project_runner2.to_global_id}") {
+ id
+ jobs {
+ nodes {
+ id
+ detailedStatus {
+ id
+ detailsPath
+ group
+ icon
+ text
+ }
+ shortSha
+ commitPath
+ finishedAt
+ duration
+ queuedDuration
+ tags
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ it 'does not execute more queries per job', :aggregate_failures do
+ # warm-up license cache and so on:
+ personal_access_token = create(:personal_access_token, user: user)
+ args = { current_user: user, token: { personal_access_token: personal_access_token } }
+ post_graphql(query, **args)
+
+ control = ActiveRecord::QueryRecorder.new(query_recorder_debug: true) { post_graphql(query, **args) }
+
+ # Add a new build to project_runner2
+ project_runner2.runner_projects << build(:ci_runner_project, runner: project_runner2, project: project3)
+ pipeline2 = create(:ci_pipeline, project: project3, source: :merge_request_event, merge_request: merge_request2,
+ ref: 'main', target_sha: 'xxx')
+ build2 = create(:ci_build, :success, name: 'Build Two', runner: project_runner2, pipeline: pipeline2)
+
+ args[:current_user] = create(:user, :admin) # do not reuse same user
+ expect { post_graphql(query, **args) }.not_to exceed_all_query_limit(control)
+
+ expect(graphql_data.count).to eq 1
+ expect(graphql_data).to match(
+ a_hash_including(
+ 'runner' => a_graphql_entity_for(
+ project_runner2,
+ jobs: { 'nodes' => containing_exactly(a_graphql_entity_for(build1), a_graphql_entity_for(build2)) }
)
))
end
diff --git a/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb b/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb
index 767e958ea82..e84a1ca4cc4 100644
--- a/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_web_url_edge_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'RunnerWebUrlEdge' do
+RSpec.describe 'RunnerWebUrlEdge', feature_category: :runner_fleet do
include GraphqlHelpers
describe 'inside a Query.group' do
diff --git a/spec/requests/api/graphql/ci/runners_spec.rb b/spec/requests/api/graphql/ci/runners_spec.rb
index 3054b866812..75d8609dc38 100644
--- a/spec/requests/api/graphql/ci/runners_spec.rb
+++ b/spec/requests/api/graphql/ci/runners_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Query.runners' do
+RSpec.describe 'Query.runners', feature_category: :runner_fleet do
include GraphqlHelpers
let_it_be(:current_user) { create_default(:user, :admin) }
@@ -48,7 +48,7 @@ RSpec.describe 'Query.runners' do
it_behaves_like 'a working graphql query'
it 'returns expected runner' do
- expect(runners_graphql_data['nodes'].map { |n| n['id'] }).to contain_exactly(expected_runner.to_global_id.to_s)
+ expect(runners_graphql_data['nodes']).to contain_exactly(a_graphql_entity_for(expected_runner))
end
end
diff --git a/spec/requests/api/graphql/ci/stages_spec.rb b/spec/requests/api/graphql/ci/stages_spec.rb
index 1edd6e58486..f4e1a69d455 100644
--- a/spec/requests/api/graphql/ci/stages_spec.rb
+++ b/spec/requests/api/graphql/ci/stages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Query.project.pipeline.stages' do
+RSpec.describe 'Query.project.pipeline.stages', feature_category: :continuous_integration do
include GraphqlHelpers
subject(:post_query) { post_graphql(query, current_user: user) }
diff --git a/spec/requests/api/graphql/ci/template_spec.rb b/spec/requests/api/graphql/ci/template_spec.rb
index 1bbef7d7f30..aaec219f734 100644
--- a/spec/requests/api/graphql/ci/template_spec.rb
+++ b/spec/requests/api/graphql/ci/template_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Querying CI template' do
+RSpec.describe 'Querying CI template', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
index 14c55e61a65..88f63fd59d7 100644
--- a/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
+++ b/spec/requests/api/graphql/container_repository/container_repository_details_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'container repository details' do
+RSpec.describe 'container repository details', feature_category: :container_registry do
include_context 'container registry tags'
include_context 'container registry client stubs'
diff --git a/spec/requests/api/graphql/crm/contacts_spec.rb b/spec/requests/api/graphql/crm/contacts_spec.rb
index a676e92dc3b..3ae19de63ed 100644
--- a/spec/requests/api/graphql/crm/contacts_spec.rb
+++ b/spec/requests/api/graphql/crm/contacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting CRM contacts' do
+RSpec.describe 'getting CRM contacts', feature_category: :service_desk do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/current_user/groups_query_spec.rb b/spec/requests/api/graphql/current_user/groups_query_spec.rb
index 6e36beb2afc..151d07ff0a7 100644
--- a/spec/requests/api/graphql/current_user/groups_query_spec.rb
+++ b/spec/requests/api/graphql/current_user/groups_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query current user groups' do
+RSpec.describe 'Query current user groups', feature_category: :subgroups do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/current_user/todos_query_spec.rb b/spec/requests/api/graphql/current_user/todos_query_spec.rb
index 5a45f0db518..f7e23aeb241 100644
--- a/spec/requests/api/graphql/current_user/todos_query_spec.rb
+++ b/spec/requests/api/graphql/current_user/todos_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query current user todos' do
+RSpec.describe 'Query current user todos', feature_category: :source_code_management do
include GraphqlHelpers
include DesignManagementTestHelpers
@@ -19,7 +19,7 @@ RSpec.describe 'Query current user todos' do
let(:fields) do
<<~QUERY
nodes {
- #{all_graphql_fields_for('todos'.classify)}
+ #{all_graphql_fields_for('todos'.classify, max_depth: 2)}
}
QUERY
end
diff --git a/spec/requests/api/graphql/current_user_query_spec.rb b/spec/requests/api/graphql/current_user_query_spec.rb
index 086a57094ca..53d2580caee 100644
--- a/spec/requests/api/graphql/current_user_query_spec.rb
+++ b/spec/requests/api/graphql/current_user_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project information' do
+RSpec.describe 'getting project information', feature_category: :authentication_and_authorization do
include GraphqlHelpers
let(:fields) do
diff --git a/spec/requests/api/graphql/current_user_todos_spec.rb b/spec/requests/api/graphql/current_user_todos_spec.rb
index da1c893ec2b..eaed51982e1 100644
--- a/spec/requests/api/graphql/current_user_todos_spec.rb
+++ b/spec/requests/api/graphql/current_user_todos_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe 'A Todoable that implements the CurrentUserTodos interface' do
+RSpec.describe 'A Todoable that implements the CurrentUserTodos interface',
+feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/custom_emoji_query_spec.rb b/spec/requests/api/graphql/custom_emoji_query_spec.rb
index 5dd5ad117b0..7b804623e01 100644
--- a/spec/requests/api/graphql/custom_emoji_query_spec.rb
+++ b/spec/requests/api/graphql/custom_emoji_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting custom emoji within namespace' do
+RSpec.describe 'getting custom emoji within namespace', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/environments/deployments_query_spec.rb b/spec/requests/api/graphql/environments/deployments_spec.rb
index 6da00057449..0022a38d2d3 100644
--- a/spec/requests/api/graphql/environments/deployments_query_spec.rb
+++ b/spec/requests/api/graphql/environments/deployments_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Environments Deployments query' do
+RSpec.describe 'Environments Deployments query', feature_category: :continuous_delivery do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
@@ -437,6 +437,43 @@ RSpec.describe 'Environments Deployments query' do
end
end
+ context 'when requesting user permissions' do
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environment(name: "#{environment.name}") {
+ deployments {
+ nodes {
+ iid
+ userPermissions {
+ updateDeployment
+ destroyDeployment
+ }
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it_behaves_like 'avoids N+1 database queries'
+
+ it 'returns user permissions of the deployments', :aggregate_failures do
+ deployments = subject.dig('data', 'project', 'environment', 'deployments', 'nodes')
+
+ deployments.each do |deployment|
+ deployment_in_record = project.deployments.find_by_iid(deployment['iid'])
+
+ expect(deployment['userPermissions']['updateDeployment'])
+ .to eq(Ability.allowed?(user, :update_deployment, deployment_in_record))
+ expect(deployment['userPermissions']['destroyDeployment'])
+ .to eq(Ability.allowed?(user, :destroy_deployment, deployment_in_record))
+ end
+ end
+ end
+
describe 'sorting and pagination' do
let(:data_path) { [:project, :environment, :deployments] }
let(:current_user) { user }
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index c1beadb6c45..7937091ea7c 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'GitlabSchema configurations' do
+RSpec.describe 'GitlabSchema configurations', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/group/container_repositories_spec.rb b/spec/requests/api/graphql/group/container_repositories_spec.rb
index 8ec321c8d7c..51d12261247 100644
--- a/spec/requests/api/graphql/group/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/group/container_repositories_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting container repositories in a group' do
+RSpec.describe 'getting container repositories in a group', feature_category: :source_code_management do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb
index daa1483e956..2c4770a31a7 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting dependency proxy blobs in a group' do
+RSpec.describe 'getting dependency proxy blobs in a group', feature_category: :dependency_proxy do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
index cc706c3051f..aca8527ba0a 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting dependency proxy settings for a group' do
+RSpec.describe 'getting dependency proxy settings for a group', feature_category: :dependency_proxy do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
index 3b2b04b1322..edff4dc1dae 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting dependency proxy image ttl policy for a group' do
+RSpec.describe 'getting dependency proxy image ttl policy for a group', feature_category: :dependency_proxy do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb b/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb
index 37ef7089c2f..d2d686104ad 100644
--- a/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb
+++ b/spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting dependency proxy manifests in a group' do
+RSpec.describe 'getting dependency proxy manifests in a group', feature_category: :dependency_proxy do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/group/group_members_spec.rb b/spec/requests/api/graphql/group/group_members_spec.rb
index 5f8becc0726..26d1fb48408 100644
--- a/spec/requests/api/graphql/group/group_members_spec.rb
+++ b/spec/requests/api/graphql/group/group_members_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting group members information' do
+RSpec.describe 'getting group members information', feature_category: :subgroups do
include GraphqlHelpers
let_it_be(:parent_group) { create(:group, :public) }
diff --git a/spec/requests/api/graphql/group/issues_spec.rb b/spec/requests/api/graphql/group/issues_spec.rb
index 26338f46611..95aeed32558 100644
--- a/spec/requests/api/graphql/group/issues_spec.rb
+++ b/spec/requests/api/graphql/group/issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting an issue list for a group' do
+RSpec.describe 'getting an issue list for a group', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/group/labels_query_spec.rb b/spec/requests/api/graphql/group/labels_query_spec.rb
index 31556ffca30..28886f8d80b 100644
--- a/spec/requests/api/graphql/group/labels_query_spec.rb
+++ b/spec/requests/api/graphql/group/labels_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting group label information' do
+RSpec.describe 'getting group label information', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:group) { create(:group, :public) }
diff --git a/spec/requests/api/graphql/group/merge_requests_spec.rb b/spec/requests/api/graphql/group/merge_requests_spec.rb
index 434b0d16569..6976685ecc0 100644
--- a/spec/requests/api/graphql/group/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/group/merge_requests_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
# Based on ee/spec/requests/api/epics_spec.rb
# Should follow closely in order to ensure all situations are covered
-RSpec.describe 'Query.group.mergeRequests' do
+RSpec.describe 'Query.group.mergeRequests', feature_category: :code_review do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/group/milestones_spec.rb b/spec/requests/api/graphql/group/milestones_spec.rb
index 7c51409f907..28cd68493c0 100644
--- a/spec/requests/api/graphql/group/milestones_spec.rb
+++ b/spec/requests/api/graphql/group/milestones_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Milestones through GroupQuery' do
+RSpec.describe 'Milestones through GroupQuery', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/group/packages_spec.rb b/spec/requests/api/graphql/group/packages_spec.rb
index cf8736db5af..0b4057c87f8 100644
--- a/spec/requests/api/graphql/group/packages_spec.rb
+++ b/spec/requests/api/graphql/group/packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting a package list for a group' do
+RSpec.describe 'getting a package list for a group', feature_category: :package_registry do
include GraphqlHelpers
let_it_be(:resource) { create(:group, :private) }
diff --git a/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb b/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb
index 4914beec870..2dfbc95bac9 100644
--- a/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb
+++ b/spec/requests/api/graphql/group/recent_issue_boards_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting group recent issue boards' do
+RSpec.describe 'getting group recent issue boards', feature_category: :team_planning do
include GraphqlHelpers
it_behaves_like 'querying a GraphQL type recent boards' do
diff --git a/spec/requests/api/graphql/group/timelogs_spec.rb b/spec/requests/api/graphql/group/timelogs_spec.rb
index 05b6ee3ff89..b67b39edff2 100644
--- a/spec/requests/api/graphql/group/timelogs_spec.rb
+++ b/spec/requests/api/graphql/group/timelogs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Timelogs through GroupQuery' do
+RSpec.describe 'Timelogs through GroupQuery', feature_category: :team_planning do
include GraphqlHelpers
describe 'Get list of timelogs from a group issues' do
diff --git a/spec/requests/api/graphql/group/work_item_types_spec.rb b/spec/requests/api/graphql/group/work_item_types_spec.rb
index 35090e2a89f..791c0fb9524 100644
--- a/spec/requests/api/graphql/group/work_item_types_spec.rb
+++ b/spec/requests/api/graphql/group/work_item_types_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting a list of work item types for a group' do
+RSpec.describe 'getting a list of work item types for a group', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:developer) { create(:user) }
diff --git a/spec/requests/api/graphql/group_query_spec.rb b/spec/requests/api/graphql/group_query_spec.rb
index 8ee5c3c5d73..bc288c0a98b 100644
--- a/spec/requests/api/graphql/group_query_spec.rb
+++ b/spec/requests/api/graphql/group_query_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
# Based on spec/requests/api/groups_spec.rb
# Should follow closely in order to ensure all situations are covered
-RSpec.describe 'getting group information' do
+RSpec.describe 'getting group information', feature_category: :subgroups do
include GraphqlHelpers
include UploadHelpers
diff --git a/spec/requests/api/graphql/issue/issue_spec.rb b/spec/requests/api/graphql/issue/issue_spec.rb
index 6e2d736f244..101de692aa5 100644
--- a/spec/requests/api/graphql/issue/issue_spec.rb
+++ b/spec/requests/api/graphql/issue/issue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.issue(id)' do
+RSpec.describe 'Query.issue(id)', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/issue_status_counts_spec.rb b/spec/requests/api/graphql/issue_status_counts_spec.rb
index 89ecbf44b10..72a1968cb27 100644
--- a/spec/requests/api/graphql/issue_status_counts_spec.rb
+++ b/spec/requests/api/graphql/issue_status_counts_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting Issue counts by status' do
+RSpec.describe 'getting Issue counts by status', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/issues_spec.rb b/spec/requests/api/graphql/issues_spec.rb
index 8838ad78f72..ba6f8ec2cab 100644
--- a/spec/requests/api/graphql/issues_spec.rb
+++ b/spec/requests/api/graphql/issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting an issue list at root level' do
+RSpec.describe 'getting an issue list at root level', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:developer) { create(:user) }
@@ -13,34 +13,81 @@ RSpec.describe 'getting an issue list at root level' do
let_it_be(:project_b) { create(:project, :repository, :private, group: group1) }
let_it_be(:project_c) { create(:project, :repository, :public, group: group2) }
let_it_be(:project_d) { create(:project, :repository, :private, group: group2) }
- let_it_be(:early_milestone) { create(:milestone, project: project_d, due_date: 10.days.from_now) }
- let_it_be(:late_milestone) { create(:milestone, project: project_c, due_date: 30.days.from_now) }
+ let_it_be(:milestone1) { create(:milestone, project: project_c, due_date: 10.days.from_now) }
+ let_it_be(:milestone2) { create(:milestone, project: project_d, due_date: 20.days.from_now) }
+ let_it_be(:milestone3) { create(:milestone, project: project_d, due_date: 30.days.from_now) }
+ let_it_be(:milestone4) { create(:milestone, project: project_a, due_date: 40.days.from_now) }
let_it_be(:priority1) { create(:label, project: project_c, priority: 1) }
let_it_be(:priority2) { create(:label, project: project_d, priority: 5) }
let_it_be(:priority3) { create(:label, project: project_a, priority: 10) }
+ let_it_be(:priority4) { create(:label, project: project_d, priority: 15) }
+
+ let_it_be(:issue_a) do
+ create(
+ :issue,
+ project: project_a,
+ labels: [priority3],
+ due_date: 1.day.ago,
+ milestone: milestone4,
+ relative_position: 1000
+ )
+ end
+
+ let_it_be(:issue_b) do
+ create(
+ :issue,
+ :with_alert,
+ project: project_b,
+ discussion_locked: true,
+ due_date: 1.day.from_now,
+ relative_position: 3000
+ )
+ end
- let_it_be(:issue_a) { create(:issue, project: project_a, labels: [priority3]) }
- let_it_be(:issue_b) { create(:issue, :with_alert, project: project_b, discussion_locked: true) }
let_it_be(:issue_c) do
create(
:issue,
+ :confidential,
project: project_c,
title: 'title matching issue plus',
labels: [priority1],
- milestone: late_milestone
+ milestone: milestone1,
+ due_date: 3.days.from_now,
+ relative_position: nil
)
end
- let_it_be(:issue_d) { create(:issue, :with_alert, project: project_d, discussion_locked: true, labels: [priority2]) }
- let_it_be(:issue_e) { create(:issue, project: project_d, milestone: early_milestone) }
+ let_it_be(:issue_d) do
+ create(
+ :issue,
+ :with_alert,
+ project: project_d,
+ discussion_locked: true,
+ labels: [priority2],
+ milestone: milestone3,
+ relative_position: 5000
+ )
+ end
- let(:issue_filter_params) { {} }
+ let_it_be(:issue_e) do
+ create(
+ :issue,
+ :confidential,
+ project: project_d,
+ milestone: milestone2,
+ due_date: 3.days.ago,
+ relative_position: nil,
+ labels: [priority2, priority4]
+ )
+ end
+ let_it_be(:issues, reload: true) { [issue_a, issue_b, issue_c, issue_d, issue_e] }
+
+ let(:issue_filter_params) { {} }
+ let(:current_user) { developer }
let(:fields) do
<<~QUERY
- nodes {
- #{all_graphql_fields_for('issues'.classify)}
- }
+ nodes { id }
QUERY
end
@@ -60,13 +107,16 @@ RSpec.describe 'getting an issue list at root level' do
end
end
+ # All new specs should be added to the shared example if the change also
+ # affects the `issues` query at the root level of the API.
+ # Shared example also used in spec/requests/api/graphql/project/issues_spec.rb
it_behaves_like 'graphql issue list request spec' do
- subject(:post_query) { post_graphql(query, current_user: current_user) }
+ let_it_be(:external_user) { create(:user) }
+
+ let(:public_projects) { [project_a, project_c] }
- let(:current_user) { developer }
let(:another_user) { reporter }
- let(:issues_data) { graphql_data['issues']['nodes'] }
- let(:issue_ids) { graphql_dig_at(issues_data, :id) }
+ let(:issue_nodes_path) { %w[issues nodes] }
# filters
let(:expected_negated_assignee_issues) { [issue_b, issue_c, issue_d, issue_e] }
@@ -77,12 +127,25 @@ RSpec.describe 'getting an issue list at root level' do
let(:unlocked_discussion_issues) { [issue_a, issue_c, issue_e] }
let(:search_title_term) { 'matching issue' }
let(:title_search_issue) { issue_c }
+ let(:confidential_issues) { [issue_c, issue_e] }
+ let(:non_confidential_issues) { [issue_a, issue_b, issue_d] }
+ let(:public_non_confidential_issues) { [issue_a] }
# sorting
let(:data_path) { [:issues] }
- let(:expected_severity_sorted_asc) { [issue_c, issue_a, issue_b, issue_e, issue_d] }
- let(:expected_priority_sorted_asc) { [issue_e, issue_c, issue_d, issue_a, issue_b] }
- let(:expected_priority_sorted_desc) { [issue_c, issue_e, issue_a, issue_d, issue_b] }
+ let(:expected_priority_sorted_asc) { [issue_c, issue_e, issue_d, issue_a, issue_b] }
+ let(:expected_priority_sorted_desc) { [issue_a, issue_d, issue_e, issue_c, issue_b] }
+ let(:expected_due_date_sorted_desc) { [issue_c, issue_b, issue_a, issue_e, issue_d] }
+ let(:expected_due_date_sorted_asc) { [issue_e, issue_a, issue_b, issue_c, issue_d] }
+ let(:expected_relative_position_sorted_asc) { [issue_a, issue_b, issue_d, issue_c, issue_e] }
+ let(:expected_label_priority_sorted_asc) { [issue_c, issue_e, issue_d, issue_a, issue_b] }
+ let(:expected_label_priority_sorted_desc) { [issue_a, issue_e, issue_d, issue_c, issue_b] }
+ let(:expected_milestone_sorted_asc) { [issue_c, issue_e, issue_d, issue_a, issue_b] }
+ let(:expected_milestone_sorted_desc) { [issue_a, issue_d, issue_e, issue_c, issue_b] }
+
+ # N+1 queries
+ let(:same_project_issue1) { issue_d }
+ let(:same_project_issue2) { issue_e }
before_all do
issue_a.assignee_ids = developer.id
@@ -90,12 +153,6 @@ RSpec.describe 'getting an issue list at root level' do
create(:award_emoji, :upvote, user: developer, awardable: issue_a)
create(:award_emoji, :upvote, user: developer, awardable: issue_c)
-
- # severity sorting
- create(:issuable_severity, issue: issue_a, severity: :unknown)
- create(:issuable_severity, issue: issue_b, severity: :low)
- create(:issuable_severity, issue: issue_d, severity: :critical)
- create(:issuable_severity, issue: issue_e, severity: :high)
end
def pagination_query(params)
@@ -107,6 +164,27 @@ RSpec.describe 'getting an issue list at root level' do
end
end
+ context 'when fetching issues from multiple projects' do
+ it 'avoids N+1 queries' do
+ post_query # warm-up
+
+ control = ActiveRecord::QueryRecorder.new { post_query }
+
+ new_private_project = create(:project, :private).tap { |project| project.add_developer(current_user) }
+ create(:issue, project: new_private_project)
+
+ expect { post_query }.not_to exceed_query_limit(control)
+ end
+ end
+
+ def execute_query
+ post_query
+ end
+
+ def post_query(request_user = current_user)
+ post_graphql(query, current_user: request_user)
+ end
+
def query(params = issue_filter_params)
graphql_query_for(
:issues,
diff --git a/spec/requests/api/graphql/jobs_query_spec.rb b/spec/requests/api/graphql/jobs_query_spec.rb
index 5907566be7f..0aea8e4c253 100644
--- a/spec/requests/api/graphql/jobs_query_spec.rb
+++ b/spec/requests/api/graphql/jobs_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting job information' do
+RSpec.describe 'getting job information', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:job) { create(:ci_build, :success, name: 'job1') }
diff --git a/spec/requests/api/graphql/merge_request/merge_request_spec.rb b/spec/requests/api/graphql/merge_request/merge_request_spec.rb
index d89f381753e..213697bacc1 100644
--- a/spec/requests/api/graphql/merge_request/merge_request_spec.rb
+++ b/spec/requests/api/graphql/merge_request/merge_request_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.merge_request(id)' do
+RSpec.describe 'Query.merge_request(id)', feature_category: :code_review do
include GraphqlHelpers
let_it_be(:project) { create(:project, :empty_repo) }
diff --git a/spec/requests/api/graphql/metadata_query_spec.rb b/spec/requests/api/graphql/metadata_query_spec.rb
index 435e1b5b596..7d1850b1b93 100644
--- a/spec/requests/api/graphql/metadata_query_spec.rb
+++ b/spec/requests/api/graphql/metadata_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project information' do
+RSpec.describe 'getting project information', feature_category: :projects do
include GraphqlHelpers
let(:query) { graphql_query_for('metadata', {}, all_graphql_fields_for('Metadata')) }
diff --git a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb
index 72ec2b8e070..4dd47142c40 100644
--- a/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb
+++ b/spec/requests/api/graphql/metrics/dashboard/annotations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Getting Metrics Dashboard Annotations' do
+RSpec.describe 'Getting Metrics Dashboard Annotations', feature_category: :metrics do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/metrics/dashboard_query_spec.rb b/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
index 1b84acff0e2..8db0844c6d7 100644
--- a/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
+++ b/spec/requests/api/graphql/metrics/dashboard_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Getting Metrics Dashboard' do
+RSpec.describe 'Getting Metrics Dashboard', feature_category: :metrics do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
@@ -26,156 +26,73 @@ RSpec.describe 'Getting Metrics Dashboard' do
)
end
- context 'with metrics_dashboard_exhaustive_validations feature flag off' do
+ context 'for anonymous user' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: false)
+ post_graphql(query, current_user: current_user)
end
- context 'for anonymous user' do
- before do
- post_graphql(query, current_user: current_user)
- end
-
- context 'requested dashboard is available' do
- let(:path) { 'config/prometheus/common_metrics.yml' }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes')
-
- expect(dashboard).to be_nil
- end
- end
- end
-
- context 'for user with developer access' do
- before do
- project.add_developer(current_user)
- post_graphql(query, current_user: current_user)
- end
-
- context 'requested dashboard is available' do
- let(:path) { 'config/prometheus/common_metrics.yml' }
-
- it_behaves_like 'a working graphql query'
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => nil)
- end
-
- context 'invalid dashboard' do
- let(:path) { '.gitlab/dashboards/metrics.yml' }
- let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "---\ndashboard: 'test'" }) }
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["panel_groups: should be an array of panel_groups objects"])
- end
- end
-
- context 'empty dashboard' do
- let(:path) { '.gitlab/dashboards/metrics.yml' }
- let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "" }) }
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
+ context 'requested dashboard is available' do
+ let(:path) { 'config/prometheus/common_metrics.yml' }
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["dashboard: can't be blank", "panel_groups: should be an array of panel_groups objects"])
- end
- end
- end
-
- context 'requested dashboard can not be found' do
- let(:path) { 'config/prometheus/i_am_not_here.yml' }
+ it_behaves_like 'a working graphql query'
- it_behaves_like 'a working graphql query'
+ it 'returns nil' do
+ dashboard = graphql_data.dig('project', 'environments', 'nodes')
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to be_nil
- end
+ expect(dashboard).to be_nil
end
end
end
- context 'with metrics_dashboard_exhaustive_validations feature flag on' do
+ context 'for user with developer access' do
before do
- stub_feature_flags(metrics_dashboard_exhaustive_validations: true)
+ project.add_developer(current_user)
+ post_graphql(query, current_user: current_user)
end
- context 'for anonymous user' do
- before do
- post_graphql(query, current_user: current_user)
- end
-
- context 'requested dashboard is available' do
- let(:path) { 'config/prometheus/common_metrics.yml' }
-
- it_behaves_like 'a working graphql query'
+ context 'requested dashboard is available' do
+ let(:path) { 'config/prometheus/common_metrics.yml' }
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes')
+ it_behaves_like 'a working graphql query'
- expect(dashboard).to be_nil
- end
- end
- end
+ it 'returns metrics dashboard' do
+ dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
- context 'for user with developer access' do
- before do
- project.add_developer(current_user)
- post_graphql(query, current_user: current_user)
+ expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => nil)
end
- context 'requested dashboard is available' do
- let(:path) { 'config/prometheus/common_metrics.yml' }
-
- it_behaves_like 'a working graphql query'
+ context 'invalid dashboard' do
+ let(:path) { '.gitlab/dashboards/metrics.yml' }
+ let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "---\ndashboard: 'test'" }) }
it 'returns metrics dashboard' do
dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => nil)
- end
-
- context 'invalid dashboard' do
- let(:path) { '.gitlab/dashboards/metrics.yml' }
- let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "---\ndashboard: 'test'" }) }
-
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
-
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["root is missing required keys: panel_groups"])
- end
+ expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["panel_groups: should be an array of panel_groups objects"])
end
+ end
- context 'empty dashboard' do
- let(:path) { '.gitlab/dashboards/metrics.yml' }
- let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "" }) }
+ context 'empty dashboard' do
+ let(:path) { '.gitlab/dashboards/metrics.yml' }
+ let(:project) { create(:project, :repository, :custom_repo, namespace: current_user.namespace, files: { path => "" }) }
- it 'returns metrics dashboard' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
+ it 'returns metrics dashboard' do
+ dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
- expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["root is missing required keys: dashboard, panel_groups"])
- end
+ expect(dashboard).to eql("path" => path, "schemaValidationWarnings" => ["dashboard: can't be blank", "panel_groups: should be an array of panel_groups objects"])
end
end
+ end
- context 'requested dashboard can not be found' do
- let(:path) { 'config/prometheus/i_am_not_here.yml' }
+ context 'requested dashboard can not be found' do
+ let(:path) { 'config/prometheus/i_am_not_here.yml' }
- it_behaves_like 'a working graphql query'
+ it_behaves_like 'a working graphql query'
- it 'returns nil' do
- dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
+ it 'returns nil' do
+ dashboard = graphql_data.dig('project', 'environments', 'nodes', 0, 'metricsDashboard')
- expect(dashboard).to be_nil
- end
+ expect(dashboard).to be_nil
end
end
end
diff --git a/spec/requests/api/graphql/milestone_spec.rb b/spec/requests/api/graphql/milestone_spec.rb
index 78e7ec39ee3..2cea9fd0408 100644
--- a/spec/requests/api/graphql/milestone_spec.rb
+++ b/spec/requests/api/graphql/milestone_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Querying a Milestone' do
+RSpec.describe 'Querying a Milestone', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:group) { create(:group, :public) }
diff --git a/spec/requests/api/graphql/multiplexed_queries_spec.rb b/spec/requests/api/graphql/multiplexed_queries_spec.rb
index f79bac6ae3b..4d615d3eaa4 100644
--- a/spec/requests/api/graphql/multiplexed_queries_spec.rb
+++ b/spec/requests/api/graphql/multiplexed_queries_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Multiplexed queries' do
+RSpec.describe 'Multiplexed queries', feature_category: :not_owned do
include GraphqlHelpers
it 'returns responses for multiple queries' do
diff --git a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
index f992e46879f..64ea6d32f5f 100644
--- a/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
+++ b/spec/requests/api/graphql/mutations/admin/sidekiq_queues/delete_jobs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues do
+RSpec.describe 'Deleting Sidekiq jobs', :clean_gitlab_redis_queues, feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
index f637ca98353..fbe6d95dfff 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create an alert issue from an alert' do
+RSpec.describe 'Create an alert issue from an alert', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
index fcef7b4e3ec..935856814c4 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/set_assignees_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting assignees of an alert' do
+RSpec.describe 'Setting assignees of an alert', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb
index 48307964345..570324a3126 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/todo/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creating a todo for the alert' do
+RSpec.describe 'Creating a todo for the alert', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb
index 802d8d6c5a1..6537747850c 100644
--- a/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/alerts/update_alert_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting the status of an alert' do
+RSpec.describe 'Setting the status of an alert', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb b/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb
index ff93da2153f..187c88363c6 100644
--- a/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creating a new HTTP Integration' do
+RSpec.describe 'Creating a new HTTP Integration', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/http_integration/destroy_spec.rb b/spec/requests/api/graphql/mutations/alert_management/http_integration/destroy_spec.rb
index 1ecb5c76b57..1c77c71daba 100644
--- a/spec/requests/api/graphql/mutations/alert_management/http_integration/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/http_integration/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Removing an HTTP Integration' do
+RSpec.describe 'Removing an HTTP Integration', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/http_integration/reset_token_spec.rb b/spec/requests/api/graphql/mutations/alert_management/http_integration/reset_token_spec.rb
index badd9412589..427277dd540 100644
--- a/spec/requests/api/graphql/mutations/alert_management/http_integration/reset_token_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/http_integration/reset_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Resetting a token on an existing HTTP Integration' do
+RSpec.describe 'Resetting a token on an existing HTTP Integration', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/http_integration/update_spec.rb b/spec/requests/api/graphql/mutations/alert_management/http_integration/update_spec.rb
index 18cbb7d8b00..a9d189d564d 100644
--- a/spec/requests/api/graphql/mutations/alert_management/http_integration/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/http_integration/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating an existing HTTP Integration' do
+RSpec.describe 'Updating an existing HTTP Integration', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb
index 4c359d9b357..3dee7f50af3 100644
--- a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creating a new Prometheus Integration' do
+RSpec.describe 'Creating a new Prometheus Integration', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
index 31053c50cac..15127843b95 100644
--- a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/reset_token_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Resetting a token on an existing Prometheus Integration' do
+RSpec.describe 'Resetting a token on an existing Prometheus Integration', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb
index ad26ec118d7..63e95f4513b 100644
--- a/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/alert_management/prometheus_integration/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating an existing Prometheus Integration' do
+RSpec.describe 'Updating an existing Prometheus Integration', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
index 3879e58cecf..fdbff0f93cd 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Adding an AwardEmoji' do
+RSpec.describe 'Adding an AwardEmoji', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
index e81621209fb..e200bfc2d18 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Removing an AwardEmoji' do
+RSpec.describe 'Removing an AwardEmoji', feature_category: :not_owned do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
index b151da72b55..6dba2b58357 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Toggling an AwardEmoji' do
+RSpec.describe 'Toggling an AwardEmoji', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/boards/create_spec.rb b/spec/requests/api/graphql/mutations/boards/create_spec.rb
index ca848c0c92f..10eb12f277f 100644
--- a/spec/requests/api/graphql/mutations/boards/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Boards::Create do
+RSpec.describe Mutations::Boards::Create, feature_category: :team_planning do
let_it_be(:parent) { create(:project) }
let_it_be(:current_user, reload: true) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/boards/destroy_spec.rb b/spec/requests/api/graphql/mutations/boards/destroy_spec.rb
index 7620da3e7e0..44924159137 100644
--- a/spec/requests/api/graphql/mutations/boards/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Boards::Destroy do
+RSpec.describe Mutations::Boards::Destroy, feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user, reload: true) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb
index 06093e9f7c2..df64caa1cfb 100644
--- a/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/issues/issue_move_list_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Reposition and move issue within board lists' do
+RSpec.describe 'Reposition and move issue within board lists', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:group) { create(:group, :private) }
diff --git a/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb b/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb
index fec9a8c6307..f5381be2741 100644
--- a/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/lists/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a label or backlog board list' do
+RSpec.describe 'Create a label or backlog board list', feature_category: :team_planning do
let_it_be(:group) { create(:group, :private) }
let_it_be(:board) { create(:board, group: group) }
diff --git a/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb b/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb
index 83309ead352..b37b1a7b935 100644
--- a/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Boards::Lists::Destroy do
+RSpec.describe Mutations::Boards::Lists::Destroy, feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user, reload: true) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb b/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb
index c7885879a9d..6a7edcd7349 100644
--- a/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/boards/lists/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Update of an existing board list' do
+RSpec.describe 'Update of an existing board list', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/branches/create_spec.rb b/spec/requests/api/graphql/mutations/branches/create_spec.rb
index 9ee2f41e8fc..32512e2ee1b 100644
--- a/spec/requests/api/graphql/mutations/branches/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/branches/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new branch' do
+RSpec.describe 'Creation of a new branch', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:group) { create(:group, :public) }
diff --git a/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb
index bdad80995ea..6cdf8788957 100644
--- a/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job/artifacts_destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'JobArtifactsDestroy' do
+RSpec.describe 'JobArtifactsDestroy', feature_category: :build_artifacts do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job/destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/job/destroy_spec.rb
index 5855eb6bb51..88dfec41d36 100644
--- a/spec/requests/api/graphql/mutations/ci/job/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'JobArtifactsDestroy' do
+RSpec.describe 'JobArtifactsDestroy', feature_category: :build_artifacts do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job_artifact/destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/job_artifact/destroy_spec.rb
index a5ec9ea343d..ac3592130b8 100644
--- a/spec/requests/api/graphql/mutations/ci/job_artifact/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_artifact/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ArtifactDestroy' do
+RSpec.describe 'ArtifactDestroy', feature_category: :build_artifacts do
include GraphqlHelpers
let(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb b/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb
index ee0f0a9bccb..468a9e57f56 100644
--- a/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_cancel_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "JobCancel" do
+RSpec.describe "JobCancel", feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job_play_spec.rb b/spec/requests/api/graphql/mutations/ci/job_play_spec.rb
index 0874e225259..014a5e0f1c7 100644
--- a/spec/requests/api/graphql/mutations/ci/job_play_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_play_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'JobPlay' do
+RSpec.describe 'JobPlay', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb b/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
index 8cf559a372a..e49ee6f3163 100644
--- a/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_retry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'JobRetry' do
+RSpec.describe 'JobRetry', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
index b2f84ab2869..490716ddbe2 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/add_project_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'CiJobTokenScopeAddProject' do
+RSpec.describe 'CiJobTokenScopeAddProject', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
@@ -60,7 +60,7 @@ RSpec.describe 'CiJobTokenScopeAddProject' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty
- end.to change { Ci::JobToken::Scope.new(project).includes?(target_project) }.from(false).to(true)
+ end.to change { Ci::JobToken::Scope.new(project).allows?(target_project) }.from(false).to(true)
end
context 'when invalid target project is provided' do
diff --git a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
index 2b0adf89f40..607c6bd85c2 100644
--- a/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_token_scope/remove_project_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'CiJobTokenScopeRemoveProject' do
+RSpec.describe 'CiJobTokenScopeRemoveProject', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, ci_outbound_job_token_scope_enabled: true).tap(&:save!) }
@@ -66,7 +66,7 @@ RSpec.describe 'CiJobTokenScopeRemoveProject' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response.dig('ciJobTokenScope', 'projects', 'nodes')).not_to be_empty
- end.to change { Ci::JobToken::Scope.new(project).includes?(target_project) }.from(true).to(false)
+ end.to change { Ci::JobToken::Scope.new(project).allows?(target_project) }.from(true).to(false)
end
context 'when invalid target project is provided' do
diff --git a/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb b/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb
index 4ddc019a2b5..6868b0ea279 100644
--- a/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/job_unschedule_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'JobUnschedule' do
+RSpec.describe 'JobUnschedule', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_cancel_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_cancel_spec.rb
index 6ec1b7ce9b6..8c1359384ed 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_cancel_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_cancel_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'PipelineCancel' do
+RSpec.describe 'PipelineCancel', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb
index 7abd5ca8772..9ddfaf83d34 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'PipelineDestroy' do
+RSpec.describe 'PipelineDestroy', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb
index f6acf29c321..e7edc86bea0 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_retry_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'PipelineRetry' do
+RSpec.describe 'PipelineRetry', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_create_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_create_spec.rb
new file mode 100644
index 00000000000..4a45d255d99
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_create_spec.rb
@@ -0,0 +1,151 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'PipelineSchedulecreate' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ **pipeline_schedule_parameters
+ }
+
+ graphql_mutation(
+ :pipeline_schedule_create,
+ variables,
+ <<-QL
+ pipelineSchedule {
+ id
+ description
+ cron
+ refForDisplay
+ active
+ cronTimezone
+ variables {
+ nodes {
+ key
+ value
+ }
+ }
+ owner {
+ id
+ }
+ }
+ errors
+ QL
+ )
+ end
+
+ let(:pipeline_schedule_parameters) do
+ {
+ description: 'created_desc',
+ cron: '0 1 * * *',
+ cronTimezone: 'UTC',
+ ref: 'patch-x',
+ active: true,
+ variables: [
+ { key: 'AAA', value: "AAA123", variableType: 'ENV_VAR' }
+ ]
+ }
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:pipeline_schedule_create) }
+
+ context 'when unauthorized' do
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(graphql_errors).not_to be_empty
+ expect(graphql_errors[0]['message'])
+ .to eq(
+ "The resource that you are attempting to access does not exist " \
+ "or you don't have permission to perform this action"
+ )
+ end
+ end
+
+ context 'when authorized' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when success' do
+ it do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+
+ expect(mutation_response['pipelineSchedule']['owner']['id']).to eq(user.to_global_id.to_s)
+
+ %w[description cron cronTimezone active].each do |key|
+ expect(mutation_response['pipelineSchedule'][key]).to eq(pipeline_schedule_parameters[key.to_sym])
+ end
+
+ expect(mutation_response['pipelineSchedule']['refForDisplay']).to eq(pipeline_schedule_parameters[:ref])
+
+ expect(mutation_response['pipelineSchedule']['variables']['nodes'][0]['key']).to eq('AAA')
+ expect(mutation_response['pipelineSchedule']['variables']['nodes'][0]['value']).to eq('AAA123')
+
+ expect(mutation_response['pipelineSchedule']['owner']['id']).to eq(user.to_global_id.to_s)
+
+ expect(mutation_response['errors']).to eq([])
+ end
+ end
+
+ context 'when failure' do
+ context 'when params are invalid' do
+ let(:pipeline_schedule_parameters) do
+ {
+ description: 'some description',
+ cron: 'abc',
+ cronTimezone: 'cCc',
+ ref: 'asd',
+ active: true,
+ variables: []
+ }
+ end
+
+ it do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+
+ expect(mutation_response['errors'])
+ .to match_array(
+ ["Cron is invalid syntax", "Cron timezone is invalid syntax"]
+ )
+ end
+ end
+
+ context 'when variables have duplicate name' do
+ before do
+ pipeline_schedule_parameters.merge!(
+ {
+ variables: [
+ { key: 'AAA', value: "AAA123", variableType: 'ENV_VAR' },
+ { key: 'AAA', value: "AAA123", variableType: 'ENV_VAR' }
+ ]
+ }
+ )
+ end
+
+ it 'returns error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+
+ expect(mutation_response['errors'])
+ .to match_array(
+ [
+ "Variables have duplicate values (AAA)"
+ ]
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_delete_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_delete_spec.rb
index b197d223463..b846ff0aec8 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'PipelineScheduleDelete' do
+RSpec.describe 'PipelineScheduleDelete', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb
new file mode 100644
index 00000000000..0e43fa024f3
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_play_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'PipelineSchedulePlay', feature_category: :continuious_integration do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline_schedule) do
+ create(
+ :ci_pipeline_schedule,
+ :every_minute,
+ project: project,
+ owner: user
+ )
+ end
+
+ let(:mutation) do
+ graphql_mutation(
+ :pipeline_schedule_play,
+ { id: pipeline_schedule.to_global_id.to_s },
+ <<-QL
+ pipelineSchedule { id, nextRunAt }
+ errors
+ QL
+ )
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:pipeline_schedule_play) }
+
+ context 'when unauthorized' do
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ expect(graphql_errors[0]['message'])
+ .to eq(
+ "The resource that you are attempting to access does not exist " \
+ "or you don't have permission to perform this action"
+ )
+ end
+ end
+
+ context 'when authorized' do
+ before do
+ project.add_maintainer(user)
+ pipeline_schedule.update_columns(next_run_at: 2.hours.ago)
+ end
+
+ context 'when mutation succeeds' do
+ it do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(mutation_response['pipelineSchedule']['id']).to include(pipeline_schedule.id.to_s)
+ new_next_run_at = DateTime.parse(mutation_response['pipelineSchedule']['nextRunAt'])
+ expect(new_next_run_at).not_to eq(pipeline_schedule.next_run_at)
+ expect(new_next_run_at).to eq(pipeline_schedule.reset.next_run_at)
+ expect(mutation_response['errors']).to eq([])
+ end
+ end
+
+ context 'when mutation fails' do
+ before do
+ allow(RunPipelineScheduleWorker).to receive(:perform_async).and_return(nil)
+ end
+
+ it do
+ expect(RunPipelineScheduleWorker)
+ .to receive(:perform_async)
+ .with(pipeline_schedule.id, user.id)
+
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(mutation_response['pipelineSchedule']).to be_nil
+ expect(mutation_response['errors']).to match_array(['Unable to schedule a pipeline to run immediately.'])
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
index 8dfbf20d00b..2d1f1565a73 100644
--- a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'PipelineScheduleTakeOwnership' do
+RSpec.describe 'PipelineScheduleTakeOwnership', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
index c808cf5ede9..7a6ee7c2ecc 100644
--- a/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/project_ci_cd_settings_update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ProjectCiCdSettingsUpdate' do
+RSpec.describe 'ProjectCiCdSettingsUpdate', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) do
diff --git a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
index 54e63df96a6..752242c3ab3 100644
--- a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'RunnersRegistrationTokenReset' do
+RSpec.describe 'RunnersRegistrationTokenReset', feature_category: :runner_fleet do
include GraphqlHelpers
let(:mutation) { graphql_mutation(:runners_registration_token_reset, input) }
diff --git a/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb b/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb
index aac8eb22771..f544cef8864 100644
--- a/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/clusters/agent_tokens/agent_tokens/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a new cluster agent token' do
+RSpec.describe 'Create a new cluster agent token', feature_category: :kubernetes_management do
include GraphqlHelpers
let_it_be(:cluster_agent) { create(:cluster_agent) }
diff --git a/spec/requests/api/graphql/mutations/clusters/agents/create_spec.rb b/spec/requests/api/graphql/mutations/clusters/agents/create_spec.rb
index c2ef2362d66..66e6c5cc629 100644
--- a/spec/requests/api/graphql/mutations/clusters/agents/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/clusters/agents/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a new cluster agent' do
+RSpec.describe 'Create a new cluster agent', feature_category: :kubernetes_management do
include GraphqlHelpers
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
index 4891e64aab8..27a566dfb8c 100644
--- a/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/clusters/agents/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Delete a cluster agent' do
+RSpec.describe 'Delete a cluster agent', feature_category: :kubernetes_management do
include GraphqlHelpers
let(:cluster_agent) { create(:cluster_agent) }
diff --git a/spec/requests/api/graphql/mutations/commits/create_spec.rb b/spec/requests/api/graphql/mutations/commits/create_spec.rb
index 619cba99c4e..e298d8284c6 100644
--- a/spec/requests/api/graphql/mutations/commits/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/commits/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new commit' do
+RSpec.describe 'Creation of a new commit', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
index ca7c1b2ce5f..97e2a5d0bf7 100644
--- a/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_expiration_policy/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating the container expiration policy' do
+RSpec.describe 'Updating the container expiration policy', feature_category: :container_registry do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb b/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
index 5a27d39ecbc..8b76c19cda6 100644
--- a/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying a container repository' do
+RSpec.describe 'Destroying a container repository', feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
@@ -80,25 +80,6 @@ RSpec.describe 'Destroying a container repository' do
it_behaves_like params[:shared_examples_name]
end
-
- context 'with container_registry_delete_repository_with_cron_worker disabled' do
- before do
- project.add_maintainer(user)
- stub_feature_flags(container_registry_delete_repository_with_cron_worker: false)
- end
-
- it 'enqueues a removal job' do
- expect(::Packages::CreateEventService)
- .to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
- expect(DeleteContainerRepositoryWorker)
- .to receive(:perform_async).with(user.id, container_repository.id)
-
- expect { subject }.to change { ::Packages::Event.count }.by(1)
-
- expect(container_repository_mutation_response).to match_schema('graphql/container_repository')
- expect(container_repository_mutation_response['status']).to eq('DELETE_SCHEDULED')
- end
- end
end
context 'with invalid id' do
diff --git a/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb b/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb
index ef00f45ef18..9e07a831076 100644
--- a/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_repository/destroy_tags_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying a container repository tags' do
+RSpec.describe 'Destroying a container repository tags', feature_category: :container_registry do
include_context 'container repository delete tags service shared context'
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb
index 66facdebe78..ea2ce8a13e2 100644
--- a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new Custom Emoji' do
+RSpec.describe 'Creation of a new Custom Emoji', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb
index 7d25206e617..ad7a043909a 100644
--- a/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Deletion of custom emoji' do
+RSpec.describe 'Deletion of custom emoji', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
index 9eb13e534ac..5d5696d3f66 100644
--- a/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/dependency_proxy/group_settings/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating the dependency proxy group settings' do
+RSpec.describe 'Updating the dependency proxy group settings', feature_category: :dependency_proxy do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
index 31ba7ecdf0e..66ee17f356c 100644
--- a/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/dependency_proxy/image_ttl_group_policy/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating the dependency proxy image ttl policy' do
+RSpec.describe 'Updating the dependency proxy image ttl policy', feature_category: :dependency_proxy do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/design_management/delete_spec.rb b/spec/requests/api/graphql/mutations/design_management/delete_spec.rb
index e2ab08b301b..7ea32ae6d19 100644
--- a/spec/requests/api/graphql/mutations/design_management/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/design_management/delete_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe "deleting designs" do
+RSpec.describe "deleting designs", feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/requests/api/graphql/mutations/design_management/move_spec.rb b/spec/requests/api/graphql/mutations/design_management/move_spec.rb
index dd121ec733e..27b5259c56b 100644
--- a/spec/requests/api/graphql/mutations/design_management/move_spec.rb
+++ b/spec/requests/api/graphql/mutations/design_management/move_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require "spec_helper"
-RSpec.describe "moving designs" do
+RSpec.describe "moving designs", feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
index d3e6c689a59..9b42b32c150 100644
--- a/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
+++ b/spec/requests/api/graphql/mutations/design_management/upload_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require "spec_helper"
-RSpec.describe "uploading designs" do
+RSpec.describe "uploading designs", feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb
index 632a934cd95..16d3bbb6518 100644
--- a/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb
+++ b/spec/requests/api/graphql/mutations/discussions/toggle_resolve_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Toggling the resolve status of a discussion' do
+RSpec.describe 'Toggling the resolve status of a discussion', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project, :public, :repository) }
diff --git a/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb b/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb
index 3771ae0746e..0e9317a4879 100644
--- a/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/environments/canary_ingress/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Update Environment Canary Ingress', :clean_gitlab_redis_cache do
+RSpec.describe 'Update Environment Canary Ingress', :clean_gitlab_redis_cache, feature_category: :deployment_management do
include GraphqlHelpers
include KubernetesHelpers
diff --git a/spec/requests/api/graphql/mutations/groups/update_spec.rb b/spec/requests/api/graphql/mutations/groups/update_spec.rb
index b9dfb8e37ab..ea3d42a4463 100644
--- a/spec/requests/api/graphql/mutations/groups/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/groups/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'GroupUpdate' do
+RSpec.describe 'GroupUpdate', feature_category: :subgroups do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
index fc3b666dd3d..49cee4f6801 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creating an incident timeline event' do
+RSpec.describe 'Creating an incident timeline event', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
index 85208869ad9..6e1a7b36736 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Removing an incident timeline event' do
+RSpec.describe 'Removing an incident timeline event', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
index 62eeecb3fb7..ca9557b3183 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Promote an incident timeline event from a comment' do
+RSpec.describe 'Promote an incident timeline event from a comment', feature_category: :incident_management do
include GraphqlHelpers
include NotesHelper
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
index 542d51b990f..163c689e399 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
@@ -2,24 +2,36 @@
require 'spec_helper'
-RSpec.describe 'Updating an incident timeline event' do
+RSpec.describe 'Updating an incident timeline event', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:tag1) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 1') }
+ let_it_be(:tag2) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 2') }
let_it_be_with_reload(:timeline_event) do
create(:incident_management_timeline_event, incident: incident, project: project)
end
+ # Pre-attach a tag to the event
+ let_it_be(:tag_link1) do
+ create(:incident_management_timeline_event_tag_link,
+ timeline_event: timeline_event,
+ timeline_event_tag: tag1
+ )
+ end
+
let(:occurred_at) { 1.minute.ago.iso8601 }
let(:note) { 'Updated note' }
+ let(:tag_names) { [] }
let(:variables) do
{
id: timeline_event.to_global_id.to_s,
note: note,
- occurred_at: occurred_at
+ occurred_at: occurred_at,
+ timeline_event_tag_names: tag_names
}
end
@@ -33,6 +45,7 @@ RSpec.describe 'Updating an incident timeline event' do
author { id username }
updatedByUser { id username }
incident { id title }
+ timelineEventTags { nodes { name } }
note
noteHtml
occurredAt
@@ -71,6 +84,9 @@ RSpec.describe 'Updating an incident timeline event' do
'id' => incident.to_global_id.to_s,
'title' => incident.title
},
+ 'timelineEventTags' => {
+ 'nodes' => []
+ },
'note' => note,
'noteHtml' => timeline_event.note_html,
'occurredAt' => occurred_at,
@@ -85,4 +101,27 @@ RSpec.describe 'Updating an incident timeline event' do
it_behaves_like 'timeline event mutation responds with validation error',
error_message: 'Timeline text is too long (maximum is 280 characters)'
end
+
+ context 'when timeline event tag names are passed' do
+ context 'when tags exist' do
+ let(:tag_names) { [tag2.name] }
+
+ it 'removes tag1 and adds tag2' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_response = mutation_response['timelineEvent']
+ tag_names = timeline_event_response['timelineEventTags']['nodes']
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(tag_names).to contain_exactly({ "name" => tag2.name })
+ end
+ end
+
+ context 'when tags do not exist' do
+ let(:tag_names) { ['some other tag'] }
+
+ it_behaves_like 'timeline event mutation responds with validation error',
+ error_message: "Following tags don't exist: [\"some other tag\"]"
+ end
+ end
end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
index 7476499d9da..b37a5331421 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creating a timeline event tag' do
+RSpec.describe 'Creating a timeline event tag', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/create_spec.rb b/spec/requests/api/graphql/mutations/issues/create_spec.rb
index a489b7424e8..d2d2f0014d6 100644
--- a/spec/requests/api/graphql/mutations/issues/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create an issue' do
+RSpec.describe 'Create an issue', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb b/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb
new file mode 100644
index 00000000000..85e21952f47
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/link_alerts_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Link alerts to an incident', feature_category: :incident_management do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:linked_alert) { create(:alert_management_alert, project: project) }
+ let_it_be(:alert1) { create(:alert_management_alert, project: project) }
+ let_it_be(:alert2) { create(:alert_management_alert, project: project) }
+ let_it_be(:incident) { create(:incident, project: project, alert_management_alerts: [linked_alert]) }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: incident.iid.to_s,
+ alert_references: [alert1.to_reference, alert2.details_url]
+ }
+
+ graphql_mutation(:issue_link_alerts, variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ alertManagementAlerts {
+ nodes {
+ iid
+ }
+ }
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:issue_link_alerts)
+ end
+
+ context 'when the user is not allowed to update the incident' do
+ it 'returns an error' do
+ error = Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors).to include(a_hash_including('message' => error))
+ end
+ end
+
+ context 'when the user is allowed to update the incident' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'links alerts to the incident' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expected_response = [linked_alert, alert1, alert2].map { |a| { 'iid' => a.iid.to_s } }
+ expect(mutation_response.dig('issue', 'alertManagementAlerts', 'nodes')).to match_array(expected_response)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/move_spec.rb b/spec/requests/api/graphql/mutations/issues/move_spec.rb
index 20ed16879f6..7d9579067b6 100644
--- a/spec/requests/api/graphql/mutations/issues/move_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/move_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Moving an issue' do
+RSpec.describe 'Moving an issue', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
index 12ab504da14..c5e6901d8f8 100644
--- a/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting an issue as confidential' do
+RSpec.describe 'Setting an issue as confidential', feature_category: :team_planning do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
index 395a490bfc3..9fce5f8497f 100644
--- a/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_crm_contacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting issues crm contacts' do
+RSpec.describe 'Setting issues crm contacts', feature_category: :service_desk do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
index 8e223b6fdaf..1a5a64e4196 100644
--- a/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_due_date_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting Due Date of an issue' do
+RSpec.describe 'Setting Due Date of an issue', feature_category: :team_planning do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb b/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb
index a81364d37b2..8fc3ad4236d 100644
--- a/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_escalation_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting the escalation status of an incident' do
+RSpec.describe 'Setting the escalation status of an incident', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb b/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
index 435ed0f9eb2..a8025894b1e 100644
--- a/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_locked_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting an issue as locked' do
+RSpec.describe 'Setting an issue as locked', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb b/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
index cd9d695bd2c..77262c7f64f 100644
--- a/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_severity_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting severity level of an incident' do
+RSpec.describe 'Setting severity level of an incident', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb
index 1edc1e0553b..6c8e5b1d15d 100644
--- a/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/set_subscription_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting subscribed status of an issue' do
+RSpec.describe 'Setting subscribed status of an issue', feature_category: :team_planning do
include GraphqlHelpers
it_behaves_like 'a subscribable resource api' do
diff --git a/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb b/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb
new file mode 100644
index 00000000000..7f6f968b1dd
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/unlink_alerts_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Unlink alert from an incident', feature_category: :incident_management do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:another_project) { create(:project) }
+ let_it_be(:internal_alert) { create(:alert_management_alert, project: project) }
+ let_it_be(:external_alert) { create(:alert_management_alert, project: another_project) }
+ let_it_be(:incident) do
+ create(:incident, project: project, alert_management_alerts: [internal_alert, external_alert])
+ end
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: incident.iid.to_s,
+ alert_id: alert_to_unlink.to_global_id.to_s
+ }
+
+ graphql_mutation(:issue_unlink_alert, variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ alertManagementAlerts {
+ nodes {
+ id
+ }
+ }
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:issue_unlink_alert)
+ end
+
+ context 'when the user is not allowed to update the incident' do
+ let(:alert_to_unlink) { internal_alert }
+
+ it 'returns an error' do
+ error = Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors).to include(a_hash_including('message' => error))
+ end
+ end
+
+ context 'when the user is allowed to update the incident' do
+ before_all do
+ project.add_developer(user)
+ end
+
+ shared_examples 'unlinking' do
+ it 'unlinks the alert from the incident', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expected_response = visible_remainded_alerts.map { |a| { 'id' => a.to_global_id.to_s } }
+ expect(mutation_response.dig('issue', 'alertManagementAlerts', 'nodes')).to match_array(expected_response)
+
+ expect(incident.reload.alert_management_alerts).to match_array(actual_remainded_alerts)
+ end
+ end
+
+ context 'when the alert is internal' do
+ let(:alert_to_unlink) { internal_alert }
+ let(:actual_remainded_alerts) { [external_alert] }
+ let(:visible_remainded_alerts) { [] } # The user cannot fetch external alerts without reading permissions
+
+ it_behaves_like 'unlinking'
+ end
+
+ context 'when the alert is external' do
+ let(:alert_to_unlink) { external_alert }
+ let(:actual_remainded_alerts) { [internal_alert] }
+ let(:visible_remainded_alerts) { [internal_alert] }
+
+ it_behaves_like 'unlinking'
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/update_spec.rb b/spec/requests/api/graphql/mutations/issues/update_spec.rb
index f38deb426b1..e51c057c182 100644
--- a/spec/requests/api/graphql/mutations/issues/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Update of an existing issue' do
+RSpec.describe 'Update of an existing issue', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb
index b438e1ba881..ab15aa97680 100644
--- a/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb
+++ b/spec/requests/api/graphql/mutations/jira_import/import_users_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Importing Jira Users' do
+RSpec.describe 'Importing Jira Users', feature_category: :integrations do
include JiraIntegrationHelpers
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
index 1508ba31e37..a864bc88afc 100644
--- a/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
+++ b/spec/requests/api/graphql/mutations/jira_import/start_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Starting a Jira Import' do
+RSpec.describe 'Starting a Jira Import', feature_category: :integrations do
include JiraIntegrationHelpers
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/mutations/labels/create_spec.rb b/spec/requests/api/graphql/mutations/labels/create_spec.rb
index d19411f6c1d..607e20af977 100644
--- a/spec/requests/api/graphql/mutations/labels/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/labels/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Labels::Create do
+RSpec.describe Mutations::Labels::Create, feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
index 3a4508489a1..c954fd50cc4 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new merge request' do
+RSpec.describe 'Creation of a new merge request', feature_category: :code_review do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb
index 2e4f35cbcde..c41161eff2b 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/reviewer_rereview_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting assignees of a merge request' do
+RSpec.describe 'Setting assignees of a merge request', feature_category: :code_review do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
index 8cec5867aca..364d13291db 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_assignees_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting assignees of a merge request', :assume_throttled do
+RSpec.describe 'Setting assignees of a merge request', :assume_throttled, feature_category: :code_review do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb
index bea2365eaa6..b48a94fbeb9 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_draft_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting Draft status of a merge request' do
+RSpec.describe 'Setting Draft status of a merge request', feature_category: :code_review do
include GraphqlHelpers
let(:current_user) { create(:user) }
@@ -64,7 +64,7 @@ RSpec.describe 'Setting Draft status of a merge request' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['mergeRequest']['title']).not_to start_with(/draft\:/)
+ expect(mutation_response['mergeRequest']['title']).not_to start_with(/draft:/)
end
it 'unmarks the merge request as `Draft`' do
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb
index a1a35bc1dcc..d88982c508c 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_locked_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting locked status of a merge request' do
+RSpec.describe 'Setting locked status of a merge request', feature_category: :code_review do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
index d7e2602bd0a..a0f0e45d1fc 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_milestone_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting milestone of a merge request' do
+RSpec.describe 'Setting milestone of a merge request', feature_category: :code_review do
include GraphqlHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb
index be786256ef2..a5be2a95c8b 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_reviewers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting reviewers of a merge request', :assume_throttled do
+RSpec.describe 'Setting reviewers of a merge request', :assume_throttled, feature_category: :code_review do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb
index d90faa605c0..daf1f529847 100644
--- a/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb
+++ b/spec/requests/api/graphql/mutations/merge_requests/set_subscription_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Setting subscribed status of a merge request' do
+RSpec.describe 'Setting subscribed status of a merge request', feature_category: :code_review do
include GraphqlHelpers
it_behaves_like 'a subscribable resource api' do
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
index 9ef443af76a..bce57b47aab 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
+RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create, feature_category: :metrics do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
index b956734068c..f505dc25dc0 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete do
+RSpec.describe Mutations::Metrics::Dashboard::Annotations::Delete, feature_category: :metrics do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
index 567d8799d93..f4f4f34fe29 100644
--- a/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/namespace/package_settings/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating the package settings' do
+RSpec.describe 'Updating the package settings', feature_category: :package_registry do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb
index a432fb17a70..3cf78230a4c 100644
--- a/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/diff_note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Adding a DiffNote' do
+RSpec.describe 'Adding a DiffNote', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb
index 8f2438cb741..0ce239d9ca5 100644
--- a/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/image_diff_note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Adding an image DiffNote' do
+RSpec.describe 'Adding an image DiffNote', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index 9c3842db31a..00e25909746 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Adding a Note' do
+RSpec.describe 'Adding a Note', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
@@ -102,6 +102,35 @@ RSpec.describe 'Adding a Note' do
it_behaves_like 'a Note mutation with confidential notes'
end
+
+ context 'as work item' do
+ let(:noteable) { create(:work_item, :issue, project: project) }
+
+ context 'when using internal param' do
+ let(:variables_extra) { { internal: true } }
+
+ it_behaves_like 'a Note mutation with confidential notes'
+ end
+
+ context 'when using deprecated confidential param' do
+ let(:variables_extra) { { confidential: true } }
+
+ it_behaves_like 'a Note mutation with confidential notes'
+ end
+
+ context 'without notes widget' do
+ let(:variables_extra) { {} }
+
+ before do
+ stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } })
+ stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] })
+ end
+
+ it_behaves_like 'a Note mutation that does not create a Note'
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ end
+ end
end
context 'when body only contains quick actions' do
diff --git a/spec/requests/api/graphql/mutations/notes/destroy_spec.rb b/spec/requests/api/graphql/mutations/notes/destroy_spec.rb
index 49f09fadfea..eb45e2aa033 100644
--- a/spec/requests/api/graphql/mutations/notes/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/destroy_spec.rb
@@ -2,17 +2,14 @@
require 'spec_helper'
-RSpec.describe 'Destroying a Note' do
+RSpec.describe 'Destroying a Note', feature_category: :team_planning do
include GraphqlHelpers
- let!(:note) { create(:note) }
- let(:mutation) do
- variables = {
- id: GitlabSchema.id_from_object(note).to_s
- }
-
- graphql_mutation(:destroy_note, variables)
- end
+ let(:noteable) { create(:work_item, :issue) }
+ let!(:note) { create(:note, noteable: noteable, project: noteable.project) }
+ let(:global_note_id) { GitlabSchema.id_from_object(note).to_s }
+ let(:variables) { { id: global_note_id } }
+ let(:mutation) { graphql_mutation(:destroy_note, variables) }
def mutation_response
graphql_mutation_response(:destroy_note)
@@ -47,5 +44,31 @@ RSpec.describe 'Destroying a Note' do
expect(mutation_response).to have_key('note')
expect(mutation_response['note']).to be_nil
end
+
+ context 'when note is system' do
+ let!(:note) { create(:note, :system) }
+
+ it 'does not destroy system note' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { Note.count }
+ end
+ end
+
+ context 'without notes widget' do
+ before do
+ stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } })
+ stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] })
+ end
+
+ it 'does not update the Note' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to not_change { Note.count }
+ end
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
+ end
end
end
diff --git a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
index c4674155aa0..e9cd27a1e20 100644
--- a/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/reposition_image_diff_note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Repositioning an ImageDiffNote' do
+RSpec.describe 'Repositioning an ImageDiffNote', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:noteable) { create(:merge_request) }
diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
index cfd0b34b815..a5cd3c8b019 100644
--- a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating an image DiffNote' do
+RSpec.describe 'Updating an image DiffNote', feature_category: :team_planning do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
index bae5c58abff..dff8a87314b 100644
--- a/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/note_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating a Note' do
+RSpec.describe 'Updating a Note', feature_category: :team_planning do
include GraphqlHelpers
let!(:note) { create(:note, note: original_body) }
@@ -36,49 +36,32 @@ RSpec.describe 'Updating a Note' do
it_behaves_like 'a Note mutation when the given resource id is not for a Note'
- it 'updates the Note' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(note.reload.note).to eq(updated_body)
- end
-
- it 'returns the updated Note' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(mutation_response['note']['body']).to eq(updated_body)
- end
+ it_behaves_like 'a Note mutation updates a note successfully'
+ it_behaves_like 'a Note mutation update with errors'
+ it_behaves_like 'a Note mutation update only with quick actions'
- context 'when there are ActiveRecord validation errors' do
- let(:params) { { body: '', confidential: true } }
+ context 'for work item' do
+ let(:noteable) { create(:work_item, :issue) }
+ let(:note) { create(:note, noteable: noteable, project: noteable.project, note: original_body) }
- it_behaves_like 'a mutation that returns errors in the response',
- errors: ["Note can't be blank", 'Confidential can not be changed for existing notes']
+ it_behaves_like 'a Note mutation updates a note successfully'
+ it_behaves_like 'a Note mutation update with errors'
+ it_behaves_like 'a Note mutation update only with quick actions'
- it 'does not update the Note' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(note.reload.note).to eq(original_body)
- expect(note.confidential).to be_falsey
- end
-
- it 'returns the original Note' do
- post_graphql_mutation(mutation, current_user: current_user)
-
- expect(mutation_response['note']['body']).to eq(original_body)
- expect(mutation_response['note']['confidential']).to be_falsey
- end
- end
+ context 'without notes widget' do
+ before do
+ stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } })
+ stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] })
+ end
- context 'when body only contains quick actions' do
- let(:updated_body) { '/close' }
+ it 'does not update the Note' do
+ post_graphql_mutation(mutation, current_user: current_user)
- it 'returns a nil note and empty errors' do
- post_graphql_mutation(mutation, current_user: current_user)
+ expect(note.reload.note).to eq(original_body)
+ end
- expect(mutation_response).to include(
- 'errors' => [],
- 'note' => nil
- )
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
end
end
end
diff --git a/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb b/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb
index 1fe01af4f1c..d0980a2b43d 100644
--- a/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/bulk_destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying multiple packages' do
+RSpec.describe 'Destroying multiple packages', feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb b/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb
index 7e00f3ca53a..2540e06be9a 100644
--- a/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/cleanup/policy/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating the packages cleanup policy' do
+RSpec.describe 'Updating the packages cleanup policy', feature_category: :package_registry do
include GraphqlHelpers
using RSpec::Parameterized::TableSyntax
diff --git a/spec/requests/api/graphql/mutations/packages/destroy_file_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_file_spec.rb
index cd25aba9e00..a4b7001fdd5 100644
--- a/spec/requests/api/graphql/mutations/packages/destroy_file_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/destroy_file_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying a package file' do
+RSpec.describe 'Destroying a package file', feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb
index 002cd634ebd..cdd05d80fc2 100644
--- a/spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/destroy_files_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying multiple package files' do
+RSpec.describe 'Destroying multiple package files', feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/mutations/packages/destroy_spec.rb b/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
index 2340a6a36d8..86167e7116f 100644
--- a/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/packages/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying a package' do
+RSpec.describe 'Destroying a package', feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/mutations/release_asset_links/create_spec.rb b/spec/requests/api/graphql/mutations/release_asset_links/create_spec.rb
index c7a4cb1ebce..418a0e47a36 100644
--- a/spec/requests/api/graphql/mutations/release_asset_links/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/release_asset_links/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new release asset link' do
+RSpec.describe 'Creation of a new release asset link', feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
diff --git a/spec/requests/api/graphql/mutations/release_asset_links/delete_spec.rb b/spec/requests/api/graphql/mutations/release_asset_links/delete_spec.rb
index 57489c82ec2..b6d2c3f691d 100644
--- a/spec/requests/api/graphql/mutations/release_asset_links/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/release_asset_links/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Deletes a release asset link' do
+RSpec.describe 'Deletes a release asset link', feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
diff --git a/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb b/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb
index 92b558d4be3..61395cc4042 100644
--- a/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/release_asset_links/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating an existing release asset link' do
+RSpec.describe 'Updating an existing release asset link', feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
diff --git a/spec/requests/api/graphql/mutations/releases/create_spec.rb b/spec/requests/api/graphql/mutations/releases/create_spec.rb
index 2541072b766..295b8c0e97e 100644
--- a/spec/requests/api/graphql/mutations/releases/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/releases/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creation of a new release' do
+RSpec.describe 'Creation of a new release', feature_category: :release_orchestration do
include GraphqlHelpers
include Presentable
diff --git a/spec/requests/api/graphql/mutations/releases/delete_spec.rb b/spec/requests/api/graphql/mutations/releases/delete_spec.rb
index eb4f0b594ea..bb398787cc6 100644
--- a/spec/requests/api/graphql/mutations/releases/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/releases/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Deleting a release' do
+RSpec.describe 'Deleting a release', feature_category: :release_orchestration do
include GraphqlHelpers
include Presentable
diff --git a/spec/requests/api/graphql/mutations/releases/update_spec.rb b/spec/requests/api/graphql/mutations/releases/update_spec.rb
index 240db764f40..2b88576a70e 100644
--- a/spec/requests/api/graphql/mutations/releases/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/releases/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating an existing release' do
+RSpec.describe 'Updating an existing release', feature_category: :release_orchestration do
include GraphqlHelpers
include Presentable
diff --git a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb
index 0c034f38dc8..cdd25f8f6ec 100644
--- a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb
+++ b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_sast_iac_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ConfigureSastIac' do
+RSpec.describe 'ConfigureSastIac', feature_category: :static_application_security_testing do
include GraphqlHelpers
let_it_be(:project) { create(:project, :test_repo) }
diff --git a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb
index 8fa6e44b208..370abf2fe00 100644
--- a/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb
+++ b/spec/requests/api/graphql/mutations/security/ci_configuration/configure_secret_detection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ConfigureSecretDetection' do
+RSpec.describe 'ConfigureSecretDetection', feature_category: :secret_detection do
include GraphqlHelpers
let_it_be(:project) { create(:project, :test_repo) }
diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
index 264fa5732c3..0b1af2bf628 100644
--- a/spec/requests/api/graphql/mutations/snippets/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Creating a Snippet' do
+RSpec.describe 'Creating a Snippet', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
index 1be8ce142ac..09e884d9412 100644
--- a/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/destroy_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Destroying a Snippet' do
+RSpec.describe 'Destroying a Snippet', feature_category: :source_code_management do
include GraphqlHelpers
let(:current_user) { snippet.author }
diff --git a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
index 77fd6cddc09..9a8c027da8a 100644
--- a/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/mark_as_spam_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Mark snippet as spam' do
+RSpec.describe 'Mark snippet as spam', feature_category: :source_code_management do
include GraphqlHelpers
include AfterNextHelpers
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
index 1a5d3620f22..fa087e6773c 100644
--- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Updating a Snippet' do
+RSpec.describe 'Updating a Snippet', feature_category: :source_code_management do
include GraphqlHelpers
include SessionHelpers
@@ -192,11 +192,18 @@ RSpec.describe 'Updating a Snippet' do
stub_session('warden.user.user.key' => [[current_user.id], current_user.authenticatable_salt])
end
- it_behaves_like 'Snowplow event tracking' do
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
let(:user) { current_user }
+ let(:property) { 'g_edit_by_snippet_ide' }
let(:namespace) { project.namespace }
- let(:category) { 'ide_edit' }
- let(:action) { 'g_edit_by_snippet_ide' }
+ let(:category) { 'Gitlab::UsageDataCounters::EditorUniqueCounter' }
+ let(:action) { 'ide_edit' }
+ let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_ide_edit' }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context]
+ end
+
let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
end
diff --git a/spec/requests/api/graphql/mutations/timelogs/create_spec.rb b/spec/requests/api/graphql/mutations/timelogs/create_spec.rb
index eea04b89783..42249818a92 100644
--- a/spec/requests/api/graphql/mutations/timelogs/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/timelogs/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a timelog' do
+RSpec.describe 'Create a timelog', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:author) { create(:user) }
@@ -11,14 +11,6 @@ RSpec.describe 'Create a timelog' do
let(:current_user) { nil }
let(:users_container) { project }
- let(:mutation) do
- graphql_mutation(:timelogCreate, {
- 'time_spent' => time_spent,
- 'spent_at' => '2022-07-08',
- 'summary' => 'Test summary',
- 'issuable_id' => issuable.to_global_id.to_s
- })
- end
let(:mutation_response) { graphql_mutation_response(:timelog_create) }
diff --git a/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb
index d304bfbdf00..d04b4d193e6 100644
--- a/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Delete a timelog' do
+RSpec.describe 'Delete a timelog', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/requests/api/graphql/mutations/todos/create_spec.rb b/spec/requests/api/graphql/mutations/todos/create_spec.rb
index aca00519682..5d7ecb3c927 100644
--- a/spec/requests/api/graphql/mutations/todos/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a todo' do
+RSpec.describe 'Create a todo', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
index dc20fde8e3c..c611c6ee2a1 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_all_done_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Marking all todos done' do
+RSpec.describe 'Marking all todos done', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
index 7f5ea71c760..60700d8024c 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Marking todos done' do
+RSpec.describe 'Marking todos done', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
index 4316bd060c1..9daa243cf8e 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_many_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Restoring many Todos' do
+RSpec.describe 'Restoring many Todos', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/todos/restore_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
index d995191c97e..868298763ec 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Restoring Todos' do
+RSpec.describe 'Restoring Todos', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/uploads/delete_spec.rb b/spec/requests/api/graphql/mutations/uploads/delete_spec.rb
index 2d1b33cc086..08dbbe23b6b 100644
--- a/spec/requests/api/graphql/mutations/uploads/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/uploads/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Delete an upload' do
+RSpec.describe 'Delete an upload', feature_category: :navigation do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb b/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb
index 28a46583d2a..eb35d310760 100644
--- a/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/user_callouts/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a user callout' do
+RSpec.describe 'Create a user callout', feature_category: :navigation do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
index e1c7fd9d60d..31d17401b9e 100644
--- a/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/user_preferences/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Mutations::UserPreferences::Update do
+RSpec.describe Mutations::UserPreferences::Update, feature_category: :users do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb
index c6a980b5cef..97bf060356a 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Create a work item from a task in a work item's description" do
+RSpec.describe "Create a work item from a task in a work item's description", feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/work_items/create_spec.rb b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
index be3917316c3..16f78b67b5c 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Create a work item' do
+RSpec.describe 'Create a work item', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
@@ -123,7 +123,7 @@ RSpec.describe 'Create a work item' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['errors'])
- .to contain_exactly(/cannot be added: only Issue and Incident can be parent of Task./)
+ .to contain_exactly(/cannot be added: is not allowed to add this type of parent/)
expect(mutation_response['workItem']).to be_nil
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/delete_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
index 0a84225a7ab..e25ff5613e4 100644
--- a/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Delete a work item' do
+RSpec.describe 'Delete a work item', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
index c44939c8d54..b1828de046f 100644
--- a/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Delete a task in a work item's description" do
+RSpec.describe "Delete a task in a work item's description", feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/mutations/work_items/update_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
index 96736457f26..14cb18d04b8 100644
--- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Update a work item' do
+RSpec.describe 'Update a work item', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
@@ -339,7 +339,7 @@ RSpec.describe 'Update a work item' do
let_it_be(:invalid_parent) { create(:work_item, :task, project: project) }
context 'when parent work item type is invalid' do
- let(:error) { "#{work_item.to_reference} cannot be added: only Issue and Incident can be parent of Task." }
+ let(:error) { "#{work_item.to_reference} cannot be added: is not allowed to add this type of parent" }
let(:input) do
{ 'hierarchyWidget' => { 'parentId' => invalid_parent.to_global_id.to_s }, 'title' => 'new title' }
end
@@ -450,7 +450,7 @@ RSpec.describe 'Update a work item' do
let(:input) { { 'hierarchyWidget' => { 'childrenIds' => children_ids } } }
let(:error) do
- "#{invalid_child.to_reference} cannot be added: only Task can be assigned as a child in hierarchy."
+ "#{invalid_child.to_reference} cannot be added: is not allowed to add this type of parent"
end
context 'when child work item type is invalid' do
@@ -632,7 +632,7 @@ RSpec.describe 'Update a work item' do
end
context 'when unsupported widget input is sent' do
- let_it_be(:test_case) { create(:work_item_type, :default, :test_case, name: 'some_test_case_name') }
+ let_it_be(:test_case) { create(:work_item_type, :default, :test_case) }
let_it_be(:work_item) { create(:work_item, work_item_type: test_case, project: project) }
let(:input) do
@@ -642,7 +642,7 @@ RSpec.describe 'Update a work item' do
end
it_behaves_like 'a mutation that returns top-level errors',
- errors: ["Following widget keys are not supported by some_test_case_name type: [:hierarchy_widget]"]
+ errors: ["Following widget keys are not supported by Test Case type: [:hierarchy_widget]"]
end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
index 55285be5a5d..999c685ac6a 100644
--- a/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/update_task_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Update a work item task' do
+RSpec.describe 'Update a work item task', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/namespace/package_settings_spec.rb b/spec/requests/api/graphql/namespace/package_settings_spec.rb
index 42fd07dbdc7..bd441032626 100644
--- a/spec/requests/api/graphql/namespace/package_settings_spec.rb
+++ b/spec/requests/api/graphql/namespace/package_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting namespace package settings in a namespace' do
+RSpec.describe 'getting namespace package settings in a namespace', feature_category: :package_registry do
include GraphqlHelpers
let_it_be(:package_settings) { create(:namespace_package_setting) }
diff --git a/spec/requests/api/graphql/namespace/projects_spec.rb b/spec/requests/api/graphql/namespace/projects_spec.rb
index d5410f1a7cb..4e12da3e3ab 100644
--- a/spec/requests/api/graphql/namespace/projects_spec.rb
+++ b/spec/requests/api/graphql/namespace/projects_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting projects' do
+RSpec.describe 'getting projects', feature_category: :projects do
include GraphqlHelpers
let(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb b/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
index 8d8a0baae36..cee698d6dc5 100644
--- a/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
+++ b/spec/requests/api/graphql/namespace/root_storage_statistics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'rendering namespace statistics' do
+RSpec.describe 'rendering namespace statistics', feature_category: :metrics do
include GraphqlHelpers
let(:namespace) { user.namespace }
diff --git a/spec/requests/api/graphql/namespace_query_spec.rb b/spec/requests/api/graphql/namespace_query_spec.rb
index e17469901c6..d12a3875ebf 100644
--- a/spec/requests/api/graphql/namespace_query_spec.rb
+++ b/spec/requests/api/graphql/namespace_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query' do
+RSpec.describe 'Query', feature_category: :subgroups do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/packages/composer_spec.rb b/spec/requests/api/graphql/packages/composer_spec.rb
index 89c01d44771..dd61582b055 100644
--- a/spec/requests/api/graphql/packages/composer_spec.rb
+++ b/spec/requests/api/graphql/packages/composer_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'package details' do
+RSpec.describe 'package details', feature_category: :package_registry do
include GraphqlHelpers
include_context 'package details setup'
diff --git a/spec/requests/api/graphql/packages/conan_spec.rb b/spec/requests/api/graphql/packages/conan_spec.rb
index 7ad85edecef..b8226c482ac 100644
--- a/spec/requests/api/graphql/packages/conan_spec.rb
+++ b/spec/requests/api/graphql/packages/conan_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'conan package details' do
+RSpec.describe 'conan package details', feature_category: :package_registry do
include GraphqlHelpers
include_context 'package details setup'
diff --git a/spec/requests/api/graphql/packages/helm_spec.rb b/spec/requests/api/graphql/packages/helm_spec.rb
index 79a589e2dc2..65b3f80d6df 100644
--- a/spec/requests/api/graphql/packages/helm_spec.rb
+++ b/spec/requests/api/graphql/packages/helm_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'helm package details' do
+RSpec.describe 'helm package details', feature_category: :package_registry do
include GraphqlHelpers
include_context 'package details setup'
diff --git a/spec/requests/api/graphql/packages/maven_spec.rb b/spec/requests/api/graphql/packages/maven_spec.rb
index b7f39efcf73..26c45ada4a1 100644
--- a/spec/requests/api/graphql/packages/maven_spec.rb
+++ b/spec/requests/api/graphql/packages/maven_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'maven package details' do
+RSpec.describe 'maven package details', feature_category: :package_registry do
include GraphqlHelpers
include_context 'package details setup'
diff --git a/spec/requests/api/graphql/packages/nuget_spec.rb b/spec/requests/api/graphql/packages/nuget_spec.rb
index 7de132d1574..1c3af46909e 100644
--- a/spec/requests/api/graphql/packages/nuget_spec.rb
+++ b/spec/requests/api/graphql/packages/nuget_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'nuget package details' do
+RSpec.describe 'nuget package details', feature_category: :package_registry do
include GraphqlHelpers
include_context 'package details setup'
diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb
index 02a3206f587..42927634119 100644
--- a/spec/requests/api/graphql/packages/package_spec.rb
+++ b/spec/requests/api/graphql/packages/package_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'package details' do
+RSpec.describe 'package details', feature_category: :package_registry do
include GraphqlHelpers
let_it_be_with_reload(:group) { create(:group) }
@@ -226,5 +226,16 @@ RSpec.describe 'package details' do
end
end
end
+
+ context 'with package that has no default status' do
+ before do
+ composer_package.update!(status: :error)
+ subject
+ end
+
+ it "does not return package's details" do
+ expect(package_details).to be_nil
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/packages/pypi_spec.rb b/spec/requests/api/graphql/packages/pypi_spec.rb
index c0e589f3597..4441f04dabb 100644
--- a/spec/requests/api/graphql/packages/pypi_spec.rb
+++ b/spec/requests/api/graphql/packages/pypi_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'pypi package details' do
+RSpec.describe 'pypi package details', feature_category: :package_registry do
include GraphqlHelpers
include_context 'package details setup'
diff --git a/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb
index a59402208ec..c4843c3cf97 100644
--- a/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alert Assignees' do
+RSpec.describe 'getting Alert Management Alert Assignees', feature_category: :projects do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb
index 29896c16f5b..3c9ec4fb60b 100644
--- a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alert Issue' do
+RSpec.describe 'getting Alert Management Alert Issue', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/alert_management/alert/metrics_dashboard_url_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/metrics_dashboard_url_spec.rb
index 352a94cfc1d..b430fdeb18f 100644
--- a/spec/requests/api/graphql/project/alert_management/alert/metrics_dashboard_url_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert/metrics_dashboard_url_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alert Assignees' do
+RSpec.describe 'getting Alert Management Alert Assignees', feature_category: :projects do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/alert_management/alert/notes_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/notes_spec.rb
index 72d185144ef..16dd0dfcfcb 100644
--- a/spec/requests/api/graphql/project/alert_management/alert/notes_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert/notes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alert Notes' do
+RSpec.describe 'getting Alert Management Alert Notes', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb
index ca58079fdfe..ad4361dfa50 100644
--- a/spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alert Assignees' do
+RSpec.describe 'getting Alert Management Alert Assignees', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb b/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb
index ecd93d169d3..7ce5bf23357 100644
--- a/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alert_status_counts_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alert counts by status' do
+RSpec.describe 'getting Alert Management Alert counts by status', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
index fe77d9dc86d..304edfbf4e4 100644
--- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting Alert Management Alerts' do
+RSpec.describe 'getting Alert Management Alerts', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:payload) { { 'custom' => { 'alert' => 'payload' }, 'runbook' => 'runbook' } }
@@ -59,6 +59,7 @@ RSpec.describe 'getting Alert Management Alerts' do
it 'returns the correct properties of the alerts' do
expect(first_alert).to include(
+ 'id' => triggered_alert.to_global_id.to_s,
'iid' => triggered_alert.iid.to_s,
'title' => triggered_alert.title,
'description' => triggered_alert.description,
@@ -80,6 +81,7 @@ RSpec.describe 'getting Alert Management Alerts' do
)
expect(second_alert).to include(
+ 'id' => resolved_alert.to_global_id.to_s,
'iid' => resolved_alert.iid.to_s,
'status' => 'RESOLVED',
'endedAt' => resolved_alert.ended_at.strftime('%Y-%m-%dT%H:%M:%SZ')
diff --git a/spec/requests/api/graphql/project/alert_management/integrations_spec.rb b/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
index 773922c1864..e8d19513a4e 100644
--- a/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/integrations_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting Alert Management Integrations' do
+RSpec.describe 'getting Alert Management Integrations', feature_category: :integrations do
include ::Gitlab::Routing
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/project/base_service_spec.rb b/spec/requests/api/graphql/project/base_service_spec.rb
index 58d10ade8cf..7b1b95eaf58 100644
--- a/spec/requests/api/graphql/project/base_service_spec.rb
+++ b/spec/requests/api/graphql/project/base_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query Jira service' do
+RSpec.describe 'query Jira service', feature_category: :authentication_and_authorization do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
index a80f683ea93..d7672cc5116 100644
--- a/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
+++ b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe 'getting merge access levels for a branch protection' do
- include_examples 'perform graphql requests for AccessLevel type objects', :merge
+RSpec.describe 'getting merge access levels for a branch protection', feature_category: :source_code_management do
+ it_behaves_like 'a GraphQL query for access levels', :merge
end
diff --git a/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
index cfdaf1096c3..65b9bc93a6b 100644
--- a/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
+++ b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-RSpec.describe 'getting push access levels for a branch protection' do
- include_examples 'perform graphql requests for AccessLevel type objects', :push
+RSpec.describe 'getting push access levels for a branch protection', feature_category: :source_code_management do
+ it_behaves_like 'a GraphQL query for access levels', :push
end
diff --git a/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb b/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb
index 8a3f546ef95..560819cb989 100644
--- a/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb
+++ b/spec/requests/api/graphql/project/branch_rules/branch_protection_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting branch protection for a branch rule' do
+RSpec.describe 'getting branch protection for a branch rule', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/branch_rules_spec.rb b/spec/requests/api/graphql/project/branch_rules_spec.rb
index ed866305445..7f6a66e2377 100644
--- a/spec/requests/api/graphql/project/branch_rules_spec.rb
+++ b/spec/requests/api/graphql/project/branch_rules_spec.rb
@@ -2,21 +2,11 @@
require 'spec_helper'
-RSpec.describe 'getting list of branch rules for a project' do
+RSpec.describe 'getting list of branch rules for a project', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:branch_name_a) { TestEnv::BRANCH_SHA.each_key.first }
- let_it_be(:branch_name_b) { 'diff-*' }
- let_it_be(:branch_rules) { [branch_rule_a, branch_rule_b] }
- let_it_be(:branch_rule_a) do
- create(:protected_branch, project: project, name: branch_name_a)
- end
-
- let_it_be(:branch_rule_b) do
- create(:protected_branch, project: project, name: branch_name_b)
- end
let(:branch_rules_data) { graphql_data_at('project', 'branchRules', 'edges') }
let(:variables) { { path: project.full_path } }
@@ -61,39 +51,39 @@ RSpec.describe 'getting list of branch rules for a project' do
end
describe 'queries' do
+ include_context 'when user tracking is disabled'
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules {
+ nodes {
+ matchingBranchesCount
+ }
+ }
+ }
+ }
+ GQL
+ end
+
before do
- # rubocop:disable RSpec/AnyInstanceOf
- allow_any_instance_of(User).to receive(:update_tracked_fields!)
- allow_any_instance_of(Users::ActivityService).to receive(:execute)
- # rubocop:enable RSpec/AnyInstanceOf
+ create(:protected_branch, project: project)
allow_next_instance_of(Resolvers::ProjectResolver) do |resolver|
allow(resolver).to receive(:resolve)
.with(full_path: project.full_path)
.and_return(project)
end
allow(project.repository).to receive(:branch_names).and_call_original
- allow(project.repository.gitaly_ref_client).to receive(:branch_names).and_call_original
end
- it 'matching_branches_count avoids N+1 queries' do
- query = <<~GQL
- query($path: ID!) {
- project(fullPath: $path) {
- branchRules {
- nodes {
- matchingBranchesCount
- }
- }
- }
- }
- GQL
-
- control = ActiveRecord::QueryRecorder.new do
+ it 'avoids N+1 queries', :use_sql_query_cache, :aggregate_failures do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
post_graphql(query, current_user: current_user, variables: variables)
end
# Verify the response includes the field
- expect_n_matching_branches_count_fields(2)
+ expect_n_matching_branches_count_fields(1)
create(:protected_branch, project: project)
create(:protected_branch, name: '*', project: project)
@@ -102,10 +92,8 @@ RSpec.describe 'getting list of branch rules for a project' do
post_graphql(query, current_user: current_user, variables: variables)
end.not_to exceed_all_query_limit(control)
+ expect_n_matching_branches_count_fields(3)
expect(project.repository).to have_received(:branch_names).at_least(2).times
- expect(project.repository.gitaly_ref_client).to have_received(:branch_names).once
-
- expect_n_matching_branches_count_fields(4)
end
def expect_n_matching_branches_count_fields(count)
@@ -118,21 +106,28 @@ RSpec.describe 'getting list of branch rules for a project' do
end
describe 'response' do
+ let_it_be(:branch_name_a) { TestEnv::BRANCH_SHA.each_key.first }
+ let_it_be(:branch_name_b) { 'diff-*' }
+ let_it_be(:branch_rules) { [branch_rule_a, branch_rule_b] }
+ let_it_be(:branch_rule_a) do
+ create(:protected_branch, project: project, name: branch_name_a, id: 9999)
+ end
+
+ let_it_be(:branch_rule_b) do
+ create(:protected_branch, project: project, name: branch_name_b, id: 10000)
+ end
+
+ # branchRules are returned in reverse order, newest first, sorted by primary_key.
+ let(:branch_rule_b_data) { branch_rules_data.dig(0, 'node') }
+ let(:branch_rule_a_data) { branch_rules_data.dig(1, 'node') }
+
before do
post_graphql(query, current_user: current_user, variables: variables)
end
it_behaves_like 'a working graphql query'
- it 'includes all fields', :aggregate_failures do
- # Responses will be sorted alphabetically. Branch names for this spec
- # come from an external constant so we check which is first
- br_a_idx = branch_name_a < branch_name_b ? 0 : 1
- br_b_idx = 1 - br_a_idx
-
- branch_rule_a_data = branch_rules_data.dig(br_a_idx, 'node')
- branch_rule_b_data = branch_rules_data.dig(br_b_idx, 'node')
-
+ it 'includes all fields', :use_sql_query_cache, :aggregate_failures do
expect(branch_rule_a_data['name']).to eq(branch_name_a)
expect(branch_rule_a_data['isDefault']).to be(true).or be(false)
expect(branch_rule_a_data['branchProtection']).to be_present
diff --git a/spec/requests/api/graphql/project/cluster_agents_spec.rb b/spec/requests/api/graphql/project/cluster_agents_spec.rb
index bb716cf2849..0881eb9cdc3 100644
--- a/spec/requests/api/graphql/project/cluster_agents_spec.rb
+++ b/spec/requests/api/graphql/project/cluster_agents_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project.cluster_agents' do
+RSpec.describe 'Project.cluster_agents', feature_category: :kubernetes_management do
include GraphqlHelpers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/requests/api/graphql/project/container_expiration_policy_spec.rb b/spec/requests/api/graphql/project/container_expiration_policy_spec.rb
index e3ea9e46353..e484e0618aa 100644
--- a/spec/requests/api/graphql/project/container_expiration_policy_spec.rb
+++ b/spec/requests/api/graphql/project/container_expiration_policy_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting a repository in a project' do
+RSpec.describe 'getting a repository in a project', feature_category: :container_registry do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/container_repositories_spec.rb b/spec/requests/api/graphql/project/container_repositories_spec.rb
index 01b117a89d8..7ccf8a6f5bf 100644
--- a/spec/requests/api/graphql/project/container_repositories_spec.rb
+++ b/spec/requests/api/graphql/project/container_repositories_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting container repositories in a project' do
+RSpec.describe 'getting container repositories in a project', feature_category: :container_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/project/deployment_spec.rb b/spec/requests/api/graphql/project/deployment_spec.rb
index e5ef7bcafbf..e3ec33ec131 100644
--- a/spec/requests/api/graphql/project/deployment_spec.rb
+++ b/spec/requests/api/graphql/project/deployment_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project Deployment query' do
+RSpec.describe 'Project Deployment query', feature_category: :continuous_delivery do
let_it_be(:project) { create(:project, :private, :repository) }
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
diff --git a/spec/requests/api/graphql/project/environments_spec.rb b/spec/requests/api/graphql/project/environments_spec.rb
index e5b6aebbf2c..618f591affa 100644
--- a/spec/requests/api/graphql/project/environments_spec.rb
+++ b/spec/requests/api/graphql/project/environments_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project Environments query' do
+RSpec.describe 'Project Environments query', feature_category: :continuous_delivery do
include GraphqlHelpers
let_it_be(:project) { create(:project, :private, :repository) }
@@ -47,6 +47,60 @@ RSpec.describe 'Project Environments query' do
expect(environment_data['environmentType']).to eq(production.environment_type)
end
+ describe 'user permissions' do
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environment(name: "#{production.name}") {
+ userPermissions {
+ updateEnvironment
+ destroyEnvironment
+ stopEnvironment
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'returns user permissions of the environment', :aggregate_failures do
+ subject
+
+ permission_data = graphql_data.dig('project', 'environment', 'userPermissions')
+ expect(permission_data['updateEnvironment']).to eq(true)
+ expect(permission_data['destroyEnvironment']).to eq(false)
+ expect(permission_data['stopEnvironment']).to eq(true)
+ end
+
+ context 'when fetching user permissions for multiple environments' do
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ environments {
+ nodes {
+ userPermissions {
+ updateEnvironment
+ destroyEnvironment
+ stopEnvironment
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'limits the result', :aggregate_failures do
+ subject
+
+ expect_graphql_errors_to_include('"userPermissions" field can be requested only ' \
+ 'for 1 Environment(s) at a time.')
+ end
+ end
+ end
+
describe 'last deployments of environments' do
::Deployment.statuses.each do |status, _|
let_it_be(:"production_#{status}_deployment") do
@@ -130,4 +184,81 @@ RSpec.describe 'Project Environments query' do
expect(multi).not_to exceed_query_limit(baseline)
end
end
+
+ describe 'nested environments' do
+ let_it_be(:testing1) { create(:environment, name: 'testing/one', project: project) }
+ let_it_be(:testing2) { create(:environment, name: 'testing/two', project: project) }
+
+ context 'with query' do
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ nestedEnvironments {
+ nodes {
+ name
+ size
+ environment {
+ name
+ path
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'can fetch nested environments' do
+ subject
+
+ nested_envs = graphql_data.dig('project', 'nestedEnvironments', 'nodes')
+ expect(nested_envs.count).to be(3)
+ expect(nested_envs.pluck('name')).to match_array(%w[production staging testing])
+ expect(nested_envs.pluck('size')).to match_array([1, 1, 2])
+ expect(nested_envs[0].dig('environment', 'name')).to eq(production.name)
+ end
+
+ context 'when user is guest' do
+ let(:user) { create(:user).tap { |u| project.add_guest(u) } }
+
+ it 'returns nothing' do
+ subject
+
+ nested_envs = graphql_data.dig('project', 'nestedEnvironments', 'nodes')
+
+ expect(nested_envs).to be_nil
+ end
+ end
+ end
+
+ context 'when using pagination' do
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ nestedEnvironments(first: 1) {
+ nodes {
+ name
+ }
+ pageInfo {
+ hasPreviousPage
+ startCursor
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+ }
+ )
+ end
+
+ it 'supports pagination' do
+ subject
+ nested_envs = graphql_data.dig('project', 'nestedEnvironments')
+ expect(nested_envs['nodes'].count).to eq(1)
+ expect(nested_envs.dig('pageInfo', 'hasNextPage')).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
index 2fe5fb593fe..e1a8304dce6 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting a detailed sentry error' do
+RSpec.describe 'getting a detailed sentry error', feature_category: :error_tracking do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
index 3ca0e35882a..2abb1f62ea9 100644
--- a/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
+++ b/spec/requests/api/graphql/project/error_tracking/sentry_errors_request_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'sentry errors requests' do
+RSpec.describe 'sentry errors requests', feature_category: :error_tracking do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/fork_details_spec.rb b/spec/requests/api/graphql/project/fork_details_spec.rb
new file mode 100644
index 00000000000..efd48b00833
--- /dev/null
+++ b/spec/requests/api/graphql/project/fork_details_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting project fork details', feature_category: :source_code_management do
+ include GraphqlHelpers
+ include ProjectForksHelper
+
+ let_it_be(:project) { create(:project, :public, :repository_private, :repository) }
+ let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
+ let_it_be(:forked_project) { fork_project(project, current_user, repository: true) }
+
+ let(:queried_project) { forked_project }
+
+ let(:query) do
+ graphql_query_for(:project,
+ { full_path: queried_project.full_path }, <<~QUERY
+ forkDetails(ref: "feature"){
+ ahead
+ behind
+ }
+ QUERY
+ )
+ end
+
+ it 'returns fork details' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['forkDetails']).to eq(
+ { 'ahead' => 1, 'behind' => 29 }
+ )
+ end
+
+ context 'when a project is not a fork' do
+ let(:queried_project) { project }
+
+ it 'does not return fork details' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['forkDetails']).to be_nil
+ end
+ end
+
+ context 'when a user cannot read the code' do
+ let_it_be(:current_user) { create(:user) }
+
+ before do
+ forked_project.update!({
+ repository_access_level: 'private',
+ merge_requests_access_level: 'private'
+ })
+ end
+
+ it 'does not return fork details' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['forkDetails']).to be_nil
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/fork_targets_spec.rb b/spec/requests/api/graphql/project/fork_targets_spec.rb
index b21a11ff4dc..f2a3901b2c6 100644
--- a/spec/requests/api/graphql/project/fork_targets_spec.rb
+++ b/spec/requests/api/graphql/project/fork_targets_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting a list of fork targets for a project' do
+RSpec.describe 'getting a list of fork targets for a project', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/project/grafana_integration_spec.rb b/spec/requests/api/graphql/project/grafana_integration_spec.rb
index e7534945e7a..1d4f52a8ace 100644
--- a/spec/requests/api/graphql/project/grafana_integration_spec.rb
+++ b/spec/requests/api/graphql/project/grafana_integration_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Getting Grafana Integration' do
+RSpec.describe 'Getting Grafana Integration', feature_category: :metrics do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb b/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
index 544d2d7bd95..7587b227d9f 100644
--- a/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
+++ b/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting incident timeline events' do
+RSpec.describe 'getting incident timeline events', feature_category: :incident_management do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
index 0444ce43c22..5ccf5c1999a 100644
--- a/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
+++ b/spec/requests/api/graphql/project/issue/design_collection/version_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)' do
+RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)',
+feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
@@ -67,7 +68,7 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
query_graphql_field(:design_at_version, dav_params, 'id filename')
end
- shared_examples :finds_dav do
+ shared_examples 'finds dav' do
it 'finds all the designs as of the given version' do
post_query
@@ -88,19 +89,19 @@ RSpec.describe 'Query.project(fullPath).issue(iid).designCollection.version(sha)
context 'by ID' do
let(:dav_params) { { id: global_id_of(design_at_version) } }
- include_examples :finds_dav
+ include_examples 'finds dav'
end
context 'by filename' do
let(:dav_params) { { filename: design.filename } }
- include_examples :finds_dav
+ include_examples 'finds dav'
end
context 'by design_id' do
let(:dav_params) { { design_id: global_id_of(design) } }
- include_examples :finds_dav
+ include_examples 'finds dav'
end
end
diff --git a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
index 46fd65db1c5..a15e4c1e792 100644
--- a/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
+++ b/spec/requests/api/graphql/project/issue/design_collection/versions_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Getting versions related to an issue' do
+RSpec.describe 'Getting versions related to an issue', feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
index 965534654ea..3765899daf2 100644
--- a/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/designs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Getting designs related to an issue' do
+RSpec.describe 'Getting designs related to an issue', feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
index 3b1eb0b4b02..69ca7030292 100644
--- a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Getting designs related to an issue' do
+RSpec.describe 'Getting designs related to an issue', feature_category: :design_management do
include GraphqlHelpers
include DesignManagementTestHelpers
diff --git a/spec/requests/api/graphql/project/issue/notes_spec.rb b/spec/requests/api/graphql/project/issue/notes_spec.rb
index 97f5261ef1d..0c7f042510e 100644
--- a/spec/requests/api/graphql/project/issue/notes_spec.rb
+++ b/spec/requests/api/graphql/project/issue/notes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting notes for an issue' do
+RSpec.describe 'getting notes for an issue', feature_category: :team_planning do
include GraphqlHelpers
let(:noteable) { create(:issue) }
diff --git a/spec/requests/api/graphql/project/issue_spec.rb b/spec/requests/api/graphql/project/issue_spec.rb
index 2415e9ef60f..bc90f9e89e6 100644
--- a/spec/requests/api/graphql/project/issue_spec.rb
+++ b/spec/requests/api/graphql/project/issue_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).issue(iid)' do
+RSpec.describe 'Query.project(fullPath).issue(iid)', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb
index 214165cb171..ec5e3c6f0de 100644
--- a/spec/requests/api/graphql/project/issues_spec.rb
+++ b/spec/requests/api/graphql/project/issues_spec.rb
@@ -2,44 +2,92 @@
require 'spec_helper'
-RSpec.describe 'getting an issue list for a project' do
+RSpec.describe 'getting an issue list for a project', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, :public, group: group) }
let_it_be(:current_user) { create(:user) }
let_it_be(:another_user) { create(:user).tap { |u| group.add_reporter(u) } }
- let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
- let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
+ let_it_be(:milestone1) { create(:milestone, project: project, due_date: 10.days.from_now) }
+ let_it_be(:milestone2) { create(:milestone, project: project, due_date: 20.days.from_now) }
+ let_it_be(:milestone3) { create(:milestone, project: project, due_date: 30.days.from_now) }
+ let_it_be(:milestone4) { create(:milestone, project: project, due_date: 40.days.from_now) }
let_it_be(:priority1) { create(:label, project: project, priority: 1) }
let_it_be(:priority2) { create(:label, project: project, priority: 5) }
let_it_be(:priority3) { create(:label, project: project, priority: 10) }
- let_it_be(:issue_a, reload: true) { create(:issue, project: project, discussion_locked: true, labels: [priority3]) }
- let_it_be(:issue_b, reload: true) { create(:issue, :with_alert, project: project, title: 'title matching issue i') }
- let_it_be(:issue_c) { create(:issue, project: project, labels: [priority1], milestone: late_milestone) }
- let_it_be(:issue_d) { create(:issue, project: project, labels: [priority2]) }
- let_it_be(:issue_e) { create(:issue, project: project, milestone: early_milestone) }
- let_it_be(:issues, reload: true) { [issue_a, issue_b, issue_c, issue_d, issue_e] }
+ let_it_be(:issue_a) do
+ create(
+ :issue,
+ project: project,
+ discussion_locked: true,
+ labels: [priority3],
+ relative_position: 1000,
+ milestone: milestone4
+ )
+ end
- let(:issue_a_gid) { issue_a.to_global_id.to_s }
- let(:issue_b_gid) { issue_b.to_global_id.to_s }
- let(:issues_data) { graphql_data['project']['issues']['nodes'] }
- let(:issue_filter_params) { {} }
+ let_it_be(:issue_b) do
+ create(
+ :issue,
+ :with_alert,
+ project: project,
+ title: 'title matching issue i',
+ due_date: 3.days.ago,
+ relative_position: 3000,
+ labels: [priority2, priority3],
+ milestone: milestone1
+ )
+ end
- let(:fields) do
- <<~QUERY
- nodes {
- #{all_graphql_fields_for('issues'.classify)}
- }
- QUERY
+ let_it_be(:issue_c) do
+ create(
+ :issue,
+ project: project,
+ labels: [priority1],
+ milestone: milestone2,
+ due_date: 1.day.ago,
+ relative_position: nil
+ )
+ end
+
+ let_it_be(:issue_d) do
+ create(:issue,
+ project: project,
+ labels: [priority2],
+ due_date: 3.days.from_now,
+ relative_position: 5000,
+ milestone: milestone3
+ )
+ end
+
+ let_it_be(:issue_e) do
+ create(
+ :issue,
+ :confidential,
+ project: project,
+ due_date: 1.day.from_now,
+ relative_position: nil
+ )
end
+ let_it_be(:issues, reload: true) { [issue_a, issue_b, issue_c, issue_d, issue_e] }
+
+ let(:issue_nodes_path) { %w[project issues nodes] }
+ let(:issue_filter_params) { {} }
+
# All new specs should be added to the shared example if the change also
# affects the `issues` query at the root level of the API.
# Shared example also used in spec/requests/api/graphql/issues_spec.rb
it_behaves_like 'graphql issue list request spec' do
- subject(:post_query) { post_graphql(query, current_user: current_user) }
+ let_it_be(:external_user) { create(:user) }
+
+ let(:public_projects) { [project] }
+
+ before_all do
+ group.add_developer(current_user)
+ end
# filters
let(:expected_negated_assignee_issues) { [issue_b, issue_c, issue_d, issue_e] }
@@ -50,24 +98,31 @@ RSpec.describe 'getting an issue list for a project' do
let(:unlocked_discussion_issues) { [issue_b, issue_c, issue_d, issue_e] }
let(:search_title_term) { 'matching issue' }
let(:title_search_issue) { issue_b }
+ let(:confidential_issues) { [issue_e] }
+ let(:non_confidential_issues) { [issue_a, issue_b, issue_c, issue_d] }
+ let(:public_non_confidential_issues) { non_confidential_issues }
# sorting
let(:data_path) { [:project, :issues] }
- let(:expected_severity_sorted_asc) { [issue_c, issue_a, issue_b, issue_e, issue_d] }
- let(:expected_priority_sorted_asc) { [issue_e, issue_c, issue_d, issue_a, issue_b] }
- let(:expected_priority_sorted_desc) { [issue_c, issue_e, issue_a, issue_d, issue_b] }
+ let(:expected_priority_sorted_asc) { [issue_b, issue_c, issue_d, issue_a, issue_e] }
+ let(:expected_priority_sorted_desc) { [issue_a, issue_d, issue_c, issue_b, issue_e] }
+ let(:expected_due_date_sorted_desc) { [issue_d, issue_e, issue_c, issue_b, issue_a] }
+ let(:expected_due_date_sorted_asc) { [issue_b, issue_c, issue_e, issue_d, issue_a] }
+ let(:expected_relative_position_sorted_asc) { [issue_a, issue_b, issue_d, issue_c, issue_e] }
+ let(:expected_label_priority_sorted_asc) { [issue_c, issue_d, issue_b, issue_a, issue_e] }
+ let(:expected_label_priority_sorted_desc) { [issue_a, issue_d, issue_b, issue_c, issue_e] }
+ let(:expected_milestone_sorted_asc) { [issue_b, issue_c, issue_d, issue_a, issue_e] }
+ let(:expected_milestone_sorted_desc) { [issue_a, issue_d, issue_c, issue_b, issue_e] }
+
+ # N+1 queries
+ let(:same_project_issue1) { issue_a }
+ let(:same_project_issue2) { issue_b }
before_all do
issue_a.assignee_ids = current_user.id
issue_b.assignee_ids = another_user.id
create(:award_emoji, :upvote, user: current_user, awardable: issue_a)
-
- # severity sorting
- create(:issuable_severity, issue: issue_a, severity: :unknown)
- create(:issuable_severity, issue: issue_b, severity: :low)
- create(:issuable_severity, issue: issue_d, severity: :critical)
- create(:issuable_severity, issue: issue_e, severity: :high)
end
def pagination_query(params)
@@ -77,591 +132,10 @@ RSpec.describe 'getting an issue list for a project' do
query_graphql_field(:issues, params, "#{page_info} nodes { id }")
)
end
- end
-
- context 'when limiting the number of results' do
- let(:query) do
- <<~GQL
- query($path: ID!, $n: Int) {
- project(fullPath: $path) {
- issues(first: $n) { #{fields} }
- }
- }
- GQL
- end
-
- let(:issue_limit) { 1 }
- let(:variables) do
- { path: project.full_path, n: issue_limit }
- end
-
- it_behaves_like 'a working graphql query' do
- before do
- post_graphql(query, current_user: current_user, variables: variables)
- end
-
- it 'only returns N issues' do
- expect(issues_data.size).to eq(issue_limit)
- end
- end
-
- context 'when no limit is provided' do
- let(:issue_limit) { nil }
-
- it 'returns all issues' do
- post_graphql(query, current_user: current_user, variables: variables)
-
- expect(issues_data.size).to be > 1
- end
- end
-
- it 'is expected to check permissions on the first issue only' do
- allow(Ability).to receive(:allowed?).and_call_original
- # Newest first, we only want to see the newest checked
- expect(Ability).not_to receive(:allowed?).with(current_user, :read_issue, issues.first)
-
- post_graphql(query, current_user: current_user, variables: variables)
- end
- end
-
- context 'when the user does not have access to the issue' do
- it 'returns nil' do
- project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
-
- post_graphql(query)
-
- expect(issues_data).to eq([])
- end
- end
-
- context 'when there is a confidential issue' do
- let_it_be(:confidential_issue) do
- create(:issue, :confidential, project: project)
- end
-
- let(:confidential_issue_gid) { confidential_issue.to_global_id.to_s }
-
- context 'when the user cannot see confidential issues' do
- it 'returns issues without confidential issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issues_data.size).to eq(5)
-
- issues_data.each do |issue|
- expect(issue['confidential']).to eq(false)
- end
- end
-
- context 'filtering for confidential issues' do
- let(:issue_filter_params) { { confidential: true } }
-
- it 'returns no issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issues_data.size).to eq(0)
- end
- end
-
- context 'filtering for non-confidential issues' do
- let(:issue_filter_params) { { confidential: false } }
-
- it 'returns correctly filtered issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issue_ids).to match_array(issues.map { |i| i.to_gid.to_s })
- end
- end
- end
-
- context 'when the user can see confidential issues' do
- before do
- project.add_developer(current_user)
- end
-
- it 'returns issues with confidential issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issues_data.size).to eq(6)
-
- confidentials = issues_data.map do |issue|
- issue['confidential']
- end
-
- expect(confidentials).to contain_exactly(true, false, false, false, false, false)
- end
-
- context 'filtering for confidential issues' do
- let(:issue_filter_params) { { confidential: true } }
-
- it 'returns correctly filtered issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issue_ids).to contain_exactly(confidential_issue_gid)
- end
- end
-
- context 'filtering for non-confidential issues' do
- let(:issue_filter_params) { { confidential: false } }
-
- it 'returns correctly filtered issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issue_ids).to match_array([issue_a, issue_b, issue_c, issue_d, issue_e].map { |i| i.to_gid.to_s })
- end
- end
- end
- end
-
- describe 'sorting and pagination' do
- let_it_be(:sort_project) { create(:project, :public) }
- let_it_be(:data_path) { [:project, :issues] }
-
- def pagination_query(params)
- graphql_query_for(
- :project,
- { full_path: sort_project.full_path },
- query_graphql_field(:issues, params, "#{page_info} nodes { iid }")
- )
- end
- def pagination_results_data(data)
- data.map { |issue| issue['iid'].to_i }
+ def post_query(request_user = current_user)
+ post_graphql(query, current_user: request_user)
end
-
- # rubocop:disable RSpec/MultipleMemoizedHelpers
- context 'when sorting by due date' do
- let_it_be(:due_issue1) { create(:issue, project: sort_project, due_date: 3.days.from_now) }
- let_it_be(:due_issue2) { create(:issue, project: sort_project, due_date: nil) }
- let_it_be(:due_issue3) { create(:issue, project: sort_project, due_date: 2.days.ago) }
- let_it_be(:due_issue4) { create(:issue, project: sort_project, due_date: nil) }
- let_it_be(:due_issue5) { create(:issue, project: sort_project, due_date: 1.day.ago) }
-
- context 'when ascending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :DUE_DATE_ASC }
- let(:first_param) { 2 }
- let(:all_records) { [due_issue3.iid, due_issue5.iid, due_issue1.iid, due_issue4.iid, due_issue2.iid] }
- end
- end
-
- context 'when descending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :DUE_DATE_DESC }
- let(:first_param) { 2 }
- let(:all_records) { [due_issue1.iid, due_issue5.iid, due_issue3.iid, due_issue4.iid, due_issue2.iid] }
- end
- end
- end
-
- context 'when sorting by relative position' do
- let_it_be(:relative_issue1) { create(:issue, project: sort_project, relative_position: 2000) }
- let_it_be(:relative_issue2) { create(:issue, project: sort_project, relative_position: nil) }
- let_it_be(:relative_issue3) { create(:issue, project: sort_project, relative_position: 1000) }
- let_it_be(:relative_issue4) { create(:issue, project: sort_project, relative_position: nil) }
- let_it_be(:relative_issue5) { create(:issue, project: sort_project, relative_position: 500) }
-
- context 'when ascending' do
- it_behaves_like 'sorted paginated query', is_reversible: true do
- let(:sort_param) { :RELATIVE_POSITION_ASC }
- let(:first_param) { 2 }
- let(:all_records) do
- [
- relative_issue5.iid, relative_issue3.iid, relative_issue1.iid,
- relative_issue2.iid, relative_issue4.iid
- ]
- end
- end
- end
- end
-
- context 'when sorting by label priority' do
- let_it_be(:label1) { create(:label, project: sort_project, priority: 1) }
- let_it_be(:label2) { create(:label, project: sort_project, priority: 5) }
- let_it_be(:label3) { create(:label, project: sort_project, priority: 10) }
- let_it_be(:label_issue1) { create(:issue, project: sort_project, labels: [label1]) }
- let_it_be(:label_issue2) { create(:issue, project: sort_project, labels: [label2]) }
- let_it_be(:label_issue3) { create(:issue, project: sort_project, labels: [label1, label3]) }
- let_it_be(:label_issue4) { create(:issue, project: sort_project) }
-
- context 'when ascending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :LABEL_PRIORITY_ASC }
- let(:first_param) { 2 }
- let(:all_records) { [label_issue3.iid, label_issue1.iid, label_issue2.iid, label_issue4.iid] }
- end
- end
-
- context 'when descending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :LABEL_PRIORITY_DESC }
- let(:first_param) { 2 }
- let(:all_records) { [label_issue2.iid, label_issue3.iid, label_issue1.iid, label_issue4.iid] }
- end
- end
- end
- # rubocop:enable RSpec/MultipleMemoizedHelpers
-
- context 'when sorting by milestone due date' do
- let_it_be(:early_milestone) { create(:milestone, project: sort_project, due_date: 10.days.from_now) }
- let_it_be(:late_milestone) { create(:milestone, project: sort_project, due_date: 30.days.from_now) }
- let_it_be(:milestone_issue1) { create(:issue, project: sort_project) }
- let_it_be(:milestone_issue2) { create(:issue, project: sort_project, milestone: early_milestone) }
- let_it_be(:milestone_issue3) { create(:issue, project: sort_project, milestone: late_milestone) }
-
- context 'when ascending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :MILESTONE_DUE_ASC }
- let(:first_param) { 2 }
- let(:all_records) { [milestone_issue2.iid, milestone_issue3.iid, milestone_issue1.iid] }
- end
- end
-
- context 'when descending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :MILESTONE_DUE_DESC }
- let(:first_param) { 2 }
- let(:all_records) { [milestone_issue3.iid, milestone_issue2.iid, milestone_issue1.iid] }
- end
- end
- end
- end
-
- context 'when fetching alert management alert' do
- let(:fields) do
- <<~QUERY
- nodes {
- iid
- alertManagementAlert {
- title
- }
- alertManagementAlerts {
- nodes {
- title
- }
- }
- }
- QUERY
- end
-
- # Alerts need to have developer permission and above
- before do
- project.add_developer(current_user)
- end
-
- it 'avoids N+1 queries' do
- control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
-
- create(:alert_management_alert, :with_incident, project: project)
-
- expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
- end
-
- it 'returns the alert data' do
- post_graphql(query, current_user: current_user)
-
- alert_titles = issues_data.map { |issue| issue.dig('alertManagementAlert', 'title') }
- expected_titles = issues.map { |issue| issue.alert_management_alert&.title }
-
- expect(alert_titles).to contain_exactly(*expected_titles)
- end
-
- it 'returns the alerts data' do
- post_graphql(query, current_user: current_user)
-
- alert_titles = issues_data.map { |issue| issue.dig('alertManagementAlerts', 'nodes') }
- expected_titles = issues.map do |issue|
- issue.alert_management_alerts.map { |alert| { 'title' => alert.title } }
- end
-
- expect(alert_titles).to contain_exactly(*expected_titles)
- end
- end
-
- context 'when fetching customer_relations_contacts' do
- let(:fields) do
- <<~QUERY
- nodes {
- id
- customerRelationsContacts {
- nodes {
- firstName
- }
- }
- }
- QUERY
- end
-
- def clean_state_query
- run_with_clean_state(query, context: { current_user: current_user })
- end
-
- it 'avoids N+1 queries' do
- create(:issue_customer_relations_contact, :for_issue, issue: issue_a)
-
- control = ActiveRecord::QueryRecorder.new(skip_cached: false) { clean_state_query }
-
- create(:issue_customer_relations_contact, :for_issue, issue: issue_a)
-
- expect { clean_state_query }.not_to exceed_all_query_limit(control)
- end
- end
-
- context 'when fetching labels' do
- let(:fields) do
- <<~QUERY
- nodes {
- id
- labels {
- nodes {
- id
- }
- }
- }
- QUERY
- end
-
- before do
- issues.each do |issue|
- # create a label for each issue we have to properly test N+1
- label = create(:label, project: project)
- issue.update!(labels: [label])
- end
- end
-
- def response_label_ids(response_data)
- response_data.map do |node|
- node['labels']['nodes'].map { |u| u['id'] }
- end.flatten
- end
-
- def labels_as_global_ids(issues)
- issues.map(&:labels).flatten.map(&:to_global_id).map(&:to_s)
- end
-
- it 'avoids N+1 queries', :aggregate_failures do
- control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
- expect(issues_data.count).to eq(5)
- expect(response_label_ids(issues_data)).to match_array(labels_as_global_ids(issues))
-
- new_issues = issues + [create(:issue, project: project, labels: [create(:label, project: project)])]
-
- expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
- # graphql_data is memoized (see spec/support/helpers/graphql_helpers.rb)
- # so we have to parse the body ourselves the second time
- issues_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['nodes']
- expect(issues_data.count).to eq(6)
- expect(response_label_ids(issues_data)).to match_array(labels_as_global_ids(new_issues))
- end
- end
-
- context 'when fetching assignees' do
- let(:fields) do
- <<~QUERY
- nodes {
- id
- assignees {
- nodes {
- id
- }
- }
- }
- QUERY
- end
-
- before do
- issues.each do |issue|
- # create an assignee for each issue we have to properly test N+1
- assignee = create(:user)
- issue.update!(assignees: [assignee])
- end
- end
-
- def response_assignee_ids(response_data)
- response_data.map do |node|
- node['assignees']['nodes'].map { |node| node['id'] }
- end.flatten
- end
-
- def assignees_as_global_ids(issues)
- issues.map(&:assignees).flatten.map(&:to_global_id).map(&:to_s)
- end
-
- it 'avoids N+1 queries', :aggregate_failures do
- control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
- expect(issues_data.count).to eq(5)
- expect(response_assignee_ids(issues_data)).to match_array(assignees_as_global_ids(issues))
-
- new_issues = issues + [create(:issue, project: project, assignees: [create(:user)])]
-
- expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
- # graphql_data is memoized (see spec/support/helpers/graphql_helpers.rb)
- # so we have to parse the body ourselves the second time
- issues_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['nodes']
- expect(issues_data.count).to eq(6)
- expect(response_assignee_ids(issues_data)).to match_array(assignees_as_global_ids(new_issues))
- end
- end
-
- context 'when fetching escalation status' do
- let_it_be(:escalation_status) { create(:incident_management_issuable_escalation_status, issue: issue_a) }
-
- let(:statuses) { issue_data.to_h { |issue| [issue['iid'], issue['escalationStatus']] } }
- let(:fields) do
- <<~QUERY
- nodes {
- id
- escalationStatus
- }
- QUERY
- end
-
- before do
- issue_a.update!(issue_type: Issue.issue_types[:incident])
- end
-
- it 'returns the escalation status values' do
- post_graphql(query, current_user: current_user)
-
- statuses = issues_data.map { |issue| issue['escalationStatus'] }
-
- expect(statuses).to contain_exactly(escalation_status.status_name.upcase.to_s, nil, nil, nil, nil)
- end
-
- it 'avoids N+1 queries', :aggregate_failures do
- base_count = ActiveRecord::QueryRecorder.new { run_with_clean_state(query, context: { current_user: current_user }) }
-
- new_incident = create(:incident, project: project)
- create(:incident_management_issuable_escalation_status, issue: new_incident)
-
- expect { run_with_clean_state(query, context: { current_user: current_user }) }.not_to exceed_query_limit(base_count)
- end
- end
-
- describe 'N+1 query checks' do
- let(:extra_iid_for_second_query) { issue_b.iid.to_s }
- let(:search_params) { { iids: [issue_a.iid.to_s] } }
-
- def execute_query
- query = graphql_query_for(
- :project,
- { full_path: project.full_path },
- query_graphql_field(
- :issues, search_params,
- query_graphql_field(:nodes, nil, requested_fields)
- )
- )
- post_graphql(query, current_user: current_user)
- end
-
- context 'when requesting `user_notes_count`' do
- let(:requested_fields) { [:user_notes_count] }
-
- before do
- create_list(:note_on_issue, 2, noteable: issue_a, project: project)
- create(:note_on_issue, noteable: issue_b, project: project)
- end
-
- include_examples 'N+1 query check'
- end
-
- context 'when requesting `user_discussions_count`' do
- let(:requested_fields) { [:user_discussions_count] }
-
- before do
- create_list(:note_on_issue, 2, noteable: issue_a, project: project)
- create(:note_on_issue, noteable: issue_b, project: project)
- end
-
- include_examples 'N+1 query check'
- end
-
- context 'when requesting `merge_requests_count`' do
- let(:requested_fields) { [:merge_requests_count] }
-
- before do
- create_list(:merge_requests_closing_issues, 2, issue: issue_a)
- create_list(:merge_requests_closing_issues, 3, issue: issue_b)
- end
-
- include_examples 'N+1 query check'
- end
-
- context 'when requesting `timelogs`' do
- let(:requested_fields) { 'timelogs { nodes { timeSpent } }' }
-
- before do
- create_list(:issue_timelog, 2, issue: issue_a)
- create(:issue_timelog, issue: issue_b)
- end
-
- include_examples 'N+1 query check'
- end
-
- context 'when requesting `closed_as_duplicate_of`' do
- let(:requested_fields) { 'closedAsDuplicateOf { id }' }
- let(:issue_a_dup) { create(:issue, project: project) }
- let(:issue_b_dup) { create(:issue, project: project) }
-
- before do
- issue_a.update!(duplicated_to_id: issue_a_dup)
- issue_b.update!(duplicated_to_id: issue_a_dup)
- end
-
- include_examples 'N+1 query check'
- end
-
- context 'when award emoji votes' do
- let(:requested_fields) { [:upvotes, :downvotes] }
-
- before do
- create_list(:award_emoji, 2, name: 'thumbsup', awardable: issue_a)
- create_list(:award_emoji, 2, name: 'thumbsdown', awardable: issue_b)
- end
-
- include_examples 'N+1 query check'
- end
-
- context 'when requesting participants' do
- let_it_be(:issue_c) { create(:issue, project: project) }
-
- let(:search_params) { { iids: [issue_a.iid.to_s, issue_c.iid.to_s] } }
- let(:requested_fields) { 'participants { nodes { name } }' }
-
- before do
- create(:award_emoji, :upvote, awardable: issue_a)
- create(:award_emoji, :upvote, awardable: issue_b)
- create(:award_emoji, :upvote, awardable: issue_c)
-
- note_with_emoji_a = create(:note_on_issue, noteable: issue_a, project: project)
- note_with_emoji_b = create(:note_on_issue, noteable: issue_b, project: project)
- note_with_emoji_c = create(:note_on_issue, noteable: issue_c, project: project)
-
- create(:award_emoji, :upvote, awardable: note_with_emoji_a)
- create(:award_emoji, :upvote, awardable: note_with_emoji_b)
- create(:award_emoji, :upvote, awardable: note_with_emoji_c)
- end
-
- # Executes 3 extra queries to fetch participant_attrs
- include_examples 'N+1 query check', threshold: 3
- end
-
- context 'when requesting labels' do
- let(:requested_fields) { ['labels { nodes { id } }'] }
-
- before do
- project_labels = create_list(:label, 2, project: project)
- group_labels = create_list(:group_label, 2, group: group)
-
- issue_a.update!(labels: [project_labels.first, group_labels.first].flatten)
- issue_b.update!(labels: [project_labels, group_labels].flatten)
- end
-
- include_examples 'N+1 query check', skip_cached: false
- end
- end
-
- def issue_ids
- graphql_dig_at(issues_data, :id)
end
def query(params = issue_filter_params)
diff --git a/spec/requests/api/graphql/project/jira_import_spec.rb b/spec/requests/api/graphql/project/jira_import_spec.rb
index 202220f4bf6..821357b6988 100644
--- a/spec/requests/api/graphql/project/jira_import_spec.rb
+++ b/spec/requests/api/graphql/project/jira_import_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query Jira import data' do
+RSpec.describe 'query Jira import data', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/jira_projects_spec.rb b/spec/requests/api/graphql/project/jira_projects_spec.rb
index 410d5b21505..3cd689deda5 100644
--- a/spec/requests/api/graphql/project/jira_projects_spec.rb
+++ b/spec/requests/api/graphql/project/jira_projects_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query Jira projects' do
+RSpec.describe 'query Jira projects', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/jira_service_spec.rb b/spec/requests/api/graphql/project/jira_service_spec.rb
index d6abe94b873..23f32d2c2d2 100644
--- a/spec/requests/api/graphql/project/jira_service_spec.rb
+++ b/spec/requests/api/graphql/project/jira_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query Jira service' do
+RSpec.describe 'query Jira service', feature_category: :integrations do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/job_spec.rb b/spec/requests/api/graphql/project/job_spec.rb
index 6edd4cf753f..ba1c8a1f616 100644
--- a/spec/requests/api/graphql/project/job_spec.rb
+++ b/spec/requests/api/graphql/project/job_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project.job' do
+RSpec.describe 'Query.project.job', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/jobs_spec.rb b/spec/requests/api/graphql/project/jobs_spec.rb
index 7d0eb203d60..d05d4a2f4b6 100644
--- a/spec/requests/api/graphql/project/jobs_spec.rb
+++ b/spec/requests/api/graphql/project/jobs_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'Query.project.jobs' do
+RSpec.describe 'Query.project.jobs', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
diff --git a/spec/requests/api/graphql/project/labels_query_spec.rb b/spec/requests/api/graphql/project/labels_query_spec.rb
index eeaaaaee575..1930a22ad30 100644
--- a/spec/requests/api/graphql/project/labels_query_spec.rb
+++ b/spec/requests/api/graphql/project/labels_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project label information' do
+RSpec.describe 'getting project label information', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/requests/api/graphql/project/languages_spec.rb b/spec/requests/api/graphql/project/languages_spec.rb
index 6ef500cde41..88a196c3ff4 100644
--- a/spec/requests/api/graphql/project/languages_spec.rb
+++ b/spec/requests/api/graphql/project/languages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Project.languages' do
+RSpec.describe 'Project.languages', feature_category: :internationalization do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb b/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb
index b1ecb32b365..36e148468bc 100644
--- a/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting notes for a merge request' do
+RSpec.describe 'getting notes for a merge request', feature_category: :code_review do
include GraphqlHelpers
let_it_be(:noteable) { create(:merge_request) }
diff --git a/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb b/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb
index 4dc272b5c2e..fb7e46cff8e 100644
--- a/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request/pipelines_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project.mergeRequests.pipelines' do
+RSpec.describe 'Query.project.mergeRequests.pipelines', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :public, :repository) }
diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb
index 6a59df81405..b7aafdf305a 100644
--- a/spec/requests/api/graphql/project/merge_request_spec.rb
+++ b/spec/requests/api/graphql/project/merge_request_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting merge request information nested in a project' do
+RSpec.describe 'getting merge request information nested in a project', feature_category: :code_review do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index 2895737ae6f..b3b4c8fe0d5 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting merge request listings nested in a project' do
+RSpec.describe 'getting merge request listings nested in a project', feature_category: :code_review do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/project/milestones_spec.rb b/spec/requests/api/graphql/project/milestones_spec.rb
index a577c367fe5..3b31da77a75 100644
--- a/spec/requests/api/graphql/project/milestones_spec.rb
+++ b/spec/requests/api/graphql/project/milestones_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting milestone listings nested in a project' do
+RSpec.describe 'getting milestone listings nested in a project', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:today) { Time.now.utc.to_date }
diff --git a/spec/requests/api/graphql/project/packages_cleanup_policy_spec.rb b/spec/requests/api/graphql/project/packages_cleanup_policy_spec.rb
index 33e1dbcba27..a7d5cc79f1a 100644
--- a/spec/requests/api/graphql/project/packages_cleanup_policy_spec.rb
+++ b/spec/requests/api/graphql/project/packages_cleanup_policy_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting the packages cleanup policy linked to a project' do
+RSpec.describe 'getting the packages cleanup policy linked to a project', feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
include GraphqlHelpers
diff --git a/spec/requests/api/graphql/project/packages_spec.rb b/spec/requests/api/graphql/project/packages_spec.rb
index d9ee997eb02..3413b80e8b4 100644
--- a/spec/requests/api/graphql/project/packages_spec.rb
+++ b/spec/requests/api/graphql/project/packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting a package list for a project' do
+RSpec.describe 'getting a package list for a project', feature_category: :package_registry do
include GraphqlHelpers
let_it_be(:resource) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb
index 41915d3cdee..0eeb382510e 100644
--- a/spec/requests/api/graphql/project/pipeline_spec.rb
+++ b/spec/requests/api/graphql/project/pipeline_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting pipeline information nested in a project' do
+RSpec.describe 'getting pipeline information nested in a project', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository, :public) }
diff --git a/spec/requests/api/graphql/project/project_members_spec.rb b/spec/requests/api/graphql/project/project_members_spec.rb
index 97a79ab3b0e..1f1d8027592 100644
--- a/spec/requests/api/graphql/project/project_members_spec.rb
+++ b/spec/requests/api/graphql/project/project_members_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project members information' do
+RSpec.describe 'getting project members information', feature_category: :projects do
include GraphqlHelpers
let_it_be(:parent_group) { create(:group, :public) }
diff --git a/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb b/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb
index 39a68d98d84..a13e96eb9d3 100644
--- a/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb
+++ b/spec/requests/api/graphql/project/project_pipeline_statistics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'rendering project pipeline statistics' do
+RSpec.describe 'rendering project pipeline statistics', feature_category: :continuous_integration do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/project_statistics_spec.rb b/spec/requests/api/graphql/project/project_statistics_spec.rb
index b57c594c64f..d078659b954 100644
--- a/spec/requests/api/graphql/project/project_statistics_spec.rb
+++ b/spec/requests/api/graphql/project/project_statistics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'rendering project statistics' do
+RSpec.describe 'rendering project statistics', feature_category: :project_statistics do
include GraphqlHelpers
let(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb b/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb
index b3daf86c4af..ae459fd26fb 100644
--- a/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb
+++ b/spec/requests/api/graphql/project/recent_issue_boards_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project recent issue boards' do
+RSpec.describe 'getting project recent issue boards', feature_category: :team_planning do
include GraphqlHelpers
it_behaves_like 'querying a GraphQL type recent boards' do
diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb
index c4899dbb71e..477388585ca 100644
--- a/spec/requests/api/graphql/project/release_spec.rb
+++ b/spec/requests/api/graphql/project/release_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).release(tagName)' do
+RSpec.describe 'Query.project(fullPath).release(tagName)', feature_category: :release_orchestration do
include GraphqlHelpers
include Presentable
diff --git a/spec/requests/api/graphql/project/releases_spec.rb b/spec/requests/api/graphql/project/releases_spec.rb
index c28a6fa7666..aa454349fcf 100644
--- a/spec/requests/api/graphql/project/releases_spec.rb
+++ b/spec/requests/api/graphql/project/releases_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.project(fullPath).releases()' do
+RSpec.describe 'Query.project(fullPath).releases()', feature_category: :release_orchestration do
include GraphqlHelpers
let_it_be(:stranger) { create(:user) }
diff --git a/spec/requests/api/graphql/project/repository/blobs_spec.rb b/spec/requests/api/graphql/project/repository/blobs_spec.rb
index ba87f1100f2..a4ee0910d30 100644
--- a/spec/requests/api/graphql/project/repository/blobs_spec.rb
+++ b/spec/requests/api/graphql/project/repository/blobs_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting blobs in a project repository' do
+RSpec.describe 'getting blobs in a project repository', feature_category: :source_code_management do
include GraphqlHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/repository_spec.rb b/spec/requests/api/graphql/project/repository_spec.rb
index b00f64c3db6..9f4d69c7b17 100644
--- a/spec/requests/api/graphql/project/repository_spec.rb
+++ b/spec/requests/api/graphql/project/repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting a repository in a project' do
+RSpec.describe 'getting a repository in a project', feature_category: :source_code_management do
include GraphqlHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/graphql/project/runners_spec.rb b/spec/requests/api/graphql/project/runners_spec.rb
new file mode 100644
index 00000000000..7304de7bec6
--- /dev/null
+++ b/spec/requests/api/graphql/project/runners_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project.runners', feature_category: :runner do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:project) { create(:project, :public, group: group) }
+ let_it_be(:instance_runner) { create(:ci_runner, :instance) }
+ let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+ let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ let_it_be(:other_project) { create(:project, :repository, :public) }
+ let_it_be(:other_project_runner) { create(:ci_runner, :project, projects: [other_project]) }
+
+ let_it_be(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ runners {
+ nodes {
+ id
+ }
+ }
+ }
+ }
+ )
+ end
+
+ context 'when the user is a project admin' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ let(:expected_ids) { [project_runner, group_runner, instance_runner].map { |g| g.to_global_id.to_s } }
+
+ it 'returns all runners available to project' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data_at(:project, :runners, :nodes).pluck('id')).to match_array(expected_ids)
+ end
+ end
+
+ context 'when the user is a project developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns no runners' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data_at(:project, :runners, :nodes)).to be_empty
+ end
+ end
+
+ context 'when on_demand_scans_runner_tags feature flag is disabled' do
+ before do
+ stub_feature_flags(on_demand_scans_runner_tags: false)
+ end
+
+ it 'returns no runners' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data_at(:project, :runners, :nodes)).to be_empty
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/terraform/state_spec.rb b/spec/requests/api/graphql/project/terraform/state_spec.rb
index 5e207ec0963..1889e7a1064 100644
--- a/spec/requests/api/graphql/project/terraform/state_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/state_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query a single terraform state' do
+RSpec.describe 'query a single terraform state', feature_category: :infrastructure_as_code do
include GraphqlHelpers
include ::API::Helpers::RelatedResourcesHelpers
diff --git a/spec/requests/api/graphql/project/terraform/states_spec.rb b/spec/requests/api/graphql/project/terraform/states_spec.rb
index cc3660bcc6b..25fc07ef509 100644
--- a/spec/requests/api/graphql/project/terraform/states_spec.rb
+++ b/spec/requests/api/graphql/project/terraform/states_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'query terraform states' do
+RSpec.describe 'query terraform states', feature_category: :infrastructure_as_code do
include GraphqlHelpers
include ::API::Helpers::RelatedResourcesHelpers
diff --git a/spec/requests/api/graphql/project/tree/tree_spec.rb b/spec/requests/api/graphql/project/tree/tree_spec.rb
index e63e0d3dd04..77b72bf39a1 100644
--- a/spec/requests/api/graphql/project/tree/tree_spec.rb
+++ b/spec/requests/api/graphql/project/tree/tree_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'getting a tree in a project' do
+RSpec.describe 'getting a tree in a project', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
@@ -166,6 +166,54 @@ RSpec.describe 'getting a tree in a project' do
end
end
+ context 'when the ref points to a SSH-signed commit' do
+ let_it_be(:ref) { 'ssh-signed-commit' }
+ let_it_be(:commit) { project.commit(ref) }
+ let_it_be(:current_user) { create(:user, email: commit.committer_email).tap { |user| project.add_owner(user) } }
+
+ let(:fields) do
+ <<~QUERY
+ tree(path:"#{path}", ref:"#{ref}") {
+ lastCommit {
+ signature {
+ ... on SshSignature {
+ #{all_graphql_fields_for('SshSignature'.classify, max_depth: 2)}
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ let_it_be(:key) do
+ create(:key, user: current_user, key: extract_public_key_from_commit(commit), expires_at: 2.days.from_now)
+ end
+
+ def extract_public_key_from_commit(commit)
+ ssh_commit = Gitlab::Ssh::Commit.new(commit)
+ signature_data = ::SSHData::Signature.parse_pem(ssh_commit.signature_text)
+ signature_data.public_key.openssh
+ end
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'returns the expected signature data' do
+ signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
+
+ expect(signature['commitSha']).to eq(commit.id)
+ expect(signature['verificationStatus']).to eq('VERIFIED')
+ expect(signature['project']['id']).to eq("gid://gitlab/Project/#{project.id}")
+ expect(signature['user']['id']).to eq("gid://gitlab/User/#{current_user.id}")
+ expect(signature['key']['id']).to eq("gid://gitlab/Key/#{key.id}")
+ expect(signature['key']['title']).to eq(key.title)
+ expect(signature['key']['createdAt']).to be_present
+ expect(signature['key']['expiresAt']).to be_present
+ expect(signature['key']['key']).to match(key.key)
+ end
+ end
+
context 'when current user is nil' do
it 'returns empty project' do
post_graphql(query, current_user: nil)
diff --git a/spec/requests/api/graphql/project/work_item_types_spec.rb b/spec/requests/api/graphql/project/work_item_types_spec.rb
index 3d30baab816..c31a260c4b8 100644
--- a/spec/requests/api/graphql/project/work_item_types_spec.rb
+++ b/spec/requests/api/graphql/project/work_item_types_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting a list of work item types for a project' do
+RSpec.describe 'getting a list of work item types for a project', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:developer) { create(:user) }
diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb
index 6d20799c9ec..a59da706a8a 100644
--- a/spec/requests/api/graphql/project/work_items_spec.rb
+++ b/spec/requests/api/graphql/project/work_items_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting a work item list for a project' do
+RSpec.describe 'getting a work item list for a project', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
@@ -93,6 +93,11 @@ RSpec.describe 'getting a work item list for a project' do
}
... on WorkItemWidgetHierarchy {
parent { id }
+ children {
+ nodes {
+ id
+ }
+ }
}
... on WorkItemWidgetLabels {
labels { nodes { id } }
@@ -112,6 +117,57 @@ RSpec.describe 'getting a work item list for a project' do
end
end
+ context 'when querying WorkItemWidgetHierarchy' do
+ let_it_be(:children) { create_list(:work_item, 3, :task, project: project) }
+ let_it_be(:child_link1) { create(:parent_link, work_item_parent: item1, work_item: children[0]) }
+
+ let(:fields) do
+ <<~GRAPHQL
+ nodes {
+ widgets {
+ type
+ ... on WorkItemWidgetHierarchy {
+ hasChildren
+ parent { id }
+ children { nodes { id } }
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ it 'executes limited number of N+1 queries' do
+ post_graphql(query, current_user: current_user) # warm-up
+
+ control = ActiveRecord::QueryRecorder.new do
+ post_graphql(query, current_user: current_user)
+ end
+
+ parent_work_items = create_list(:work_item, 2, project: project)
+ create(:parent_link, work_item_parent: parent_work_items[0], work_item: children[1])
+ create(:parent_link, work_item_parent: parent_work_items[1], work_item: children[2])
+
+ # There are 2 extra queries for fetching the children field
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/363569
+ expect { post_graphql(query, current_user: current_user) }
+ .not_to exceed_query_limit(control).with_threshold(2)
+ end
+
+ it 'avoids N+1 queries when children are added to a work item' do
+ post_graphql(query, current_user: current_user) # warm-up
+
+ control = ActiveRecord::QueryRecorder.new do
+ post_graphql(query, current_user: current_user)
+ end
+
+ create(:parent_link, work_item_parent: item1, work_item: children[1])
+ create(:parent_link, work_item_parent: item1, work_item: children[2])
+
+ expect { post_graphql(query, current_user: current_user) }
+ .not_to exceed_query_limit(control)
+ end
+ end
+
it_behaves_like 'a working graphql query' do
before do
post_graphql(query, current_user: current_user)
@@ -188,6 +244,60 @@ RSpec.describe 'getting a work item list for a project' do
end
end
+ describe 'fetching work item notes widget' do
+ let(:item_filter_params) { { iid: item2.iid.to_s } }
+ let(:fields) do
+ <<~GRAPHQL
+ edges {
+ node {
+ widgets {
+ type
+ ... on WorkItemWidgetNotes {
+ system: discussions(filter: ONLY_ACTIVITY, first: 10) { nodes { id notes { nodes { id system internal body } } } },
+ comments: discussions(filter: ONLY_COMMENTS, first: 10) { nodes { id notes { nodes { id system internal body } } } },
+ all_notes: discussions(filter: ALL_NOTES, first: 10) { nodes { id notes { nodes { id system internal body } } } }
+ }
+ }
+ }
+ }
+ GRAPHQL
+ end
+
+ before do
+ create_notes(item1, "some note1")
+ create_notes(item2, "some note2")
+ end
+
+ shared_examples 'fetches work item notes' do |user_comments_count:, system_notes_count:|
+ it "fetches notes" do
+ post_graphql(query, current_user: current_user)
+
+ all_widgets = graphql_dig_at(items_data, :node, :widgets)
+ notes_widget = all_widgets.find { |x| x["type"] == "NOTES" }
+
+ all_notes = graphql_dig_at(notes_widget["all_notes"], :nodes)
+ system_notes = graphql_dig_at(notes_widget["system"], :nodes)
+ comments = graphql_dig_at(notes_widget["comments"], :nodes)
+
+ expect(comments.count).to eq(user_comments_count)
+ expect(system_notes.count).to eq(system_notes_count)
+ expect(all_notes.count).to eq(user_comments_count + system_notes_count)
+ end
+ end
+
+ context 'when user has permission to view internal notes' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it_behaves_like 'fetches work item notes', user_comments_count: 2, system_notes_count: 5
+ end
+
+ context 'when user cannot view internal notes' do
+ it_behaves_like 'fetches work item notes', user_comments_count: 1, system_notes_count: 5
+ end
+ end
+
def item_ids
graphql_dig_at(items_data, :node, :id)
end
@@ -199,4 +309,26 @@ RSpec.describe 'getting a work item list for a project' do
query_graphql_field('workItems', params, fields)
)
end
+
+ def create_notes(work_item, note_body)
+ create(:note, system: true, project: work_item.project, noteable: work_item)
+
+ disc_start = create(:discussion_note_on_issue, noteable: work_item, project: work_item.project, note: note_body)
+ create(:note,
+ discussion_id: disc_start.discussion_id, noteable: work_item,
+ project: work_item.project, note: "reply on #{note_body}")
+
+ create(:resource_label_event, user: current_user, issue: work_item, label: label1, action: 'add')
+ create(:resource_label_event, user: current_user, issue: work_item, label: label1, action: 'remove')
+
+ create(:resource_milestone_event, issue: work_item, milestone: milestone1, action: 'add')
+ create(:resource_milestone_event, issue: work_item, milestone: milestone1, action: 'remove')
+
+ # confidential notes are currently available only on issues and epics
+ conf_disc_start = create(:discussion_note_on_issue, :confidential,
+ noteable: work_item, project: work_item.project, note: "confidential #{note_body}")
+ create(:note, :confidential,
+ discussion_id: conf_disc_start.discussion_id, noteable: work_item,
+ project: work_item.project, note: "reply on confidential #{note_body}")
+ end
end
diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb
index d1b990629a1..281a08e6548 100644
--- a/spec/requests/api/graphql/project_query_spec.rb
+++ b/spec/requests/api/graphql/project_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting project information' do
+RSpec.describe 'getting project information', feature_category: :projects do
include GraphqlHelpers
let_it_be(:group) { create(:group) }
diff --git a/spec/requests/api/graphql/query_spec.rb b/spec/requests/api/graphql/query_spec.rb
index 359c599cd3a..2b9d66ec744 100644
--- a/spec/requests/api/graphql/query_spec.rb
+++ b/spec/requests/api/graphql/query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query' do
+RSpec.describe 'Query', feature_category: :not_owned do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/read_only_spec.rb b/spec/requests/api/graphql/read_only_spec.rb
index d2a45603886..aec8d3151c8 100644
--- a/spec/requests/api/graphql/read_only_spec.rb
+++ b/spec/requests/api/graphql/read_only_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Requests on a read-only node' do
+RSpec.describe 'Requests on a read-only node', feature_category: :database do
context 'when db is read-only' do
before do
allow(Gitlab::Database).to receive(:read_only?) { true }
diff --git a/spec/requests/api/graphql/snippets_spec.rb b/spec/requests/api/graphql/snippets_spec.rb
index 9edd805678a..3cd95b0841c 100644
--- a/spec/requests/api/graphql/snippets_spec.rb
+++ b/spec/requests/api/graphql/snippets_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'snippets' do
+RSpec.describe 'snippets', feature_category: :source_code_management do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/tasks/task_completion_status_spec.rb b/spec/requests/api/graphql/tasks/task_completion_status_spec.rb
index 5f4d2aec718..ea89487c176 100644
--- a/spec/requests/api/graphql/tasks/task_completion_status_spec.rb
+++ b/spec/requests/api/graphql/tasks/task_completion_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting task completion status information' do
+RSpec.describe 'getting task completion status information', feature_category: :team_planning do
include GraphqlHelpers
description_0_done = '- [ ] task 1\n- [ ] task 2'
diff --git a/spec/requests/api/graphql/terraform/state/delete_spec.rb b/spec/requests/api/graphql/terraform/state/delete_spec.rb
index ba0619ea611..f4af402492c 100644
--- a/spec/requests/api/graphql/terraform/state/delete_spec.rb
+++ b/spec/requests/api/graphql/terraform/state/delete_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'delete a terraform state' do
+RSpec.describe 'delete a terraform state', feature_category: :infrastructure_as_code do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/terraform/state/lock_spec.rb b/spec/requests/api/graphql/terraform/state/lock_spec.rb
index e4d3b6336ab..4219f4f4651 100644
--- a/spec/requests/api/graphql/terraform/state/lock_spec.rb
+++ b/spec/requests/api/graphql/terraform/state/lock_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'lock a terraform state' do
+RSpec.describe 'lock a terraform state', feature_category: :infrastructure_as_code do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/terraform/state/unlock_spec.rb b/spec/requests/api/graphql/terraform/state/unlock_spec.rb
index e90730f2d8f..84ccc09711d 100644
--- a/spec/requests/api/graphql/terraform/state/unlock_spec.rb
+++ b/spec/requests/api/graphql/terraform/state/unlock_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'unlock a terraform state' do
+RSpec.describe 'unlock a terraform state', feature_category: :infrastructure_as_code do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/graphql/todo_query_spec.rb b/spec/requests/api/graphql/todo_query_spec.rb
index 7fe19448083..b8ce065dbbb 100644
--- a/spec/requests/api/graphql/todo_query_spec.rb
+++ b/spec/requests/api/graphql/todo_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Todo Query' do
+RSpec.describe 'Todo Query', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:current_user) { nil }
diff --git a/spec/requests/api/graphql/usage_trends_measurements_spec.rb b/spec/requests/api/graphql/usage_trends_measurements_spec.rb
index 78a4321f522..68b97fbb130 100644
--- a/spec/requests/api/graphql/usage_trends_measurements_spec.rb
+++ b/spec/requests/api/graphql/usage_trends_measurements_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'UsageTrendsMeasurements' do
+RSpec.describe 'UsageTrendsMeasurements', feature_category: :devops_reports do
include GraphqlHelpers
let(:current_user) { create(:user, :admin) }
diff --git a/spec/requests/api/graphql/user/group_member_query_spec.rb b/spec/requests/api/graphql/user/group_member_query_spec.rb
index e47cef8cc37..d09cb319877 100644
--- a/spec/requests/api/graphql/user/group_member_query_spec.rb
+++ b/spec/requests/api/graphql/user/group_member_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'GroupMember' do
+RSpec.describe 'GroupMember', feature_category: :subgroups do
include GraphqlHelpers
let_it_be(:member) { create(:group_member, :developer) }
diff --git a/spec/requests/api/graphql/user/project_member_query_spec.rb b/spec/requests/api/graphql/user/project_member_query_spec.rb
index 01827e94d5d..1baa7815793 100644
--- a/spec/requests/api/graphql/user/project_member_query_spec.rb
+++ b/spec/requests/api/graphql/user/project_member_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'ProjectMember' do
+RSpec.describe 'ProjectMember', feature_category: :subgroups do
include GraphqlHelpers
let_it_be(:member) { create(:project_member, :developer) }
diff --git a/spec/requests/api/graphql/user/starred_projects_query_spec.rb b/spec/requests/api/graphql/user/starred_projects_query_spec.rb
index 75a17ed34c4..7d4284300d8 100644
--- a/spec/requests/api/graphql/user/starred_projects_query_spec.rb
+++ b/spec/requests/api/graphql/user/starred_projects_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Getting starredProjects of the user' do
+RSpec.describe 'Getting starredProjects of the user', feature_category: :projects do
include GraphqlHelpers
let(:query) do
diff --git a/spec/requests/api/graphql/user_query_spec.rb b/spec/requests/api/graphql/user_query_spec.rb
index 8f286180617..ca319ed1b2e 100644
--- a/spec/requests/api/graphql/user_query_spec.rb
+++ b/spec/requests/api/graphql/user_query_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'getting user information' do
+RSpec.describe 'getting user information', feature_category: :user_management do
include GraphqlHelpers
let(:query) do
diff --git a/spec/requests/api/graphql/user_spec.rb b/spec/requests/api/graphql/user_spec.rb
index a3b2b750bc3..2e1e4971767 100644
--- a/spec/requests/api/graphql/user_spec.rb
+++ b/spec/requests/api/graphql/user_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User' do
+RSpec.describe 'User', feature_category: :users do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
diff --git a/spec/requests/api/graphql/users_spec.rb b/spec/requests/api/graphql/users_spec.rb
index 79ee3c2cb57..83c360fdaf8 100644
--- a/spec/requests/api/graphql/users_spec.rb
+++ b/spec/requests/api/graphql/users_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Users' do
+RSpec.describe 'Users', feature_category: :user_management do
include GraphqlHelpers
let_it_be(:user0) { create(:user, created_at: 1.day.ago) }
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index a55de6adfb2..df7dbaea420 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Query.work_item(id)' do
+RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
include GraphqlHelpers
let_it_be(:developer) { create(:user) }
@@ -116,6 +116,7 @@ RSpec.describe 'Query.work_item(id)' do
id
}
}
+ hasChildren
}
}
GRAPHQL
@@ -132,7 +133,8 @@ RSpec.describe 'Query.work_item(id)' do
[
hash_including('id' => child_link1.work_item.to_gid.to_s),
hash_including('id' => child_link2.work_item.to_gid.to_s)
- ]) }
+ ]) },
+ 'hasChildren' => true
)
)
)
@@ -165,7 +167,8 @@ RSpec.describe 'Query.work_item(id)' do
'children' => { 'nodes' => match_array(
[
hash_including('id' => child_link1.work_item.to_gid.to_s)
- ]) }
+ ]) },
+ 'hasChildren' => true
)
)
)
@@ -183,7 +186,8 @@ RSpec.describe 'Query.work_item(id)' do
hash_including(
'type' => 'HIERARCHY',
'parent' => hash_including('id' => parent_link.work_item_parent.to_gid.to_s),
- 'children' => { 'nodes' => match_array([]) }
+ 'children' => { 'nodes' => match_array([]) },
+ 'hasChildren' => false
)
)
)
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index 1c1ae73ddfe..d7724371cce 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe 'GraphQL' do
+RSpec.describe 'GraphQL', feature_category: :not_owned do
include GraphqlHelpers
include AfterNextHelpers
@@ -25,12 +25,12 @@ RSpec.describe 'GraphQL' do
"query_analysis.used_fields" => ['Query.echo'],
"query_analysis.used_deprecated_fields" => [],
# query_fingerprint starts with operation name
- query_fingerprint: %r{^anonymous\/},
+ query_fingerprint: %r{^anonymous/},
duration_s: kind_of(Numeric),
trace_type: 'execute_query',
operation_name: nil,
# operation_fingerprint starts with operation name
- operation_fingerprint: %r{^anonymous\/},
+ operation_fingerprint: %r{^anonymous/},
is_mutation: false,
variables: variables.to_s,
query_string: query
diff --git a/spec/requests/api/group_avatar_spec.rb b/spec/requests/api/group_avatar_spec.rb
index 50379d29b09..9a0e79ee9f8 100644
--- a/spec/requests/api/group_avatar_spec.rb
+++ b/spec/requests/api/group_avatar_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupAvatar do
+RSpec.describe API::GroupAvatar, feature_category: :subgroups do
def avatar_path(group)
"/groups/#{ERB::Util.url_encode(group.full_path)}/avatar"
end
diff --git a/spec/requests/api/group_boards_spec.rb b/spec/requests/api/group_boards_spec.rb
index cc110aa4017..01f0e6e2061 100644
--- a/spec/requests/api/group_boards_spec.rb
+++ b/spec/requests/api/group_boards_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupBoards do
+RSpec.describe API::GroupBoards, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:non_member) { create(:user) }
let_it_be(:guest) { create(:user) }
diff --git a/spec/requests/api/group_clusters_spec.rb b/spec/requests/api/group_clusters_spec.rb
index 8e127bf0710..68c3af01e56 100644
--- a/spec/requests/api/group_clusters_spec.rb
+++ b/spec/requests/api/group_clusters_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupClusters do
+RSpec.describe API::GroupClusters, feature_category: :kubernetes_management do
include KubernetesHelpers
let(:current_user) { create(:user) }
diff --git a/spec/requests/api/group_container_repositories_spec.rb b/spec/requests/api/group_container_repositories_spec.rb
index 82daab0e5e8..cd88b060a3a 100644
--- a/spec/requests/api/group_container_repositories_spec.rb
+++ b/spec/requests/api/group_container_repositories_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupContainerRepositories do
+RSpec.describe API::GroupContainerRepositories, feature_category: :container_registry do
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, :private, group: group) }
let_it_be(:reporter) { create(:user) }
@@ -35,7 +35,9 @@ RSpec.describe API::GroupContainerRepositories do
describe 'GET /groups/:id/registry/repositories' do
let(:url) { "/groups/#{group.id}/registry/repositories" }
- let(:snowplow_gitlab_standard_context) { { user: api_user, namespace: group } }
+ let(:snowplow_gitlab_standard_context) do
+ { user: api_user, namespace: group, property: 'i_package_container_user' }
+ end
subject { get api(url, api_user) }
diff --git a/spec/requests/api/group_debian_distributions_spec.rb b/spec/requests/api/group_debian_distributions_spec.rb
index 21c5f2f09a0..57b481e4f9f 100644
--- a/spec/requests/api/group_debian_distributions_spec.rb
+++ b/spec/requests/api/group_debian_distributions_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::GroupDebianDistributions do
+RSpec.describe API::GroupDebianDistributions, feature_category: :package_registry do
include HttpBasicAuthHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/group_export_spec.rb b/spec/requests/api/group_export_spec.rb
index 83c34204c78..565365506a7 100644
--- a/spec/requests/api/group_export_spec.rb
+++ b/spec/requests/api/group_export_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupExport do
+RSpec.describe API::GroupExport, feature_category: :importers do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/group_import_spec.rb b/spec/requests/api/group_import_spec.rb
index efad6334518..07c21c93585 100644
--- a/spec/requests/api/group_import_spec.rb
+++ b/spec/requests/api/group_import_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupImport do
+RSpec.describe API::GroupImport, feature_category: :importers do
include WorkhorseHelpers
include_context 'workhorse headers'
@@ -198,12 +198,6 @@ RSpec.describe API::GroupImport do
include_examples 'when all params are correct'
include_examples 'when some params are missing'
end
-
- it "doesn't attempt to migrate file to object storage" do
- expect(ObjectStorage::BackgroundMoveWorker).not_to receive(:perform_async)
-
- subject
- end
end
context 'with object storage enabled' do
diff --git a/spec/requests/api/group_labels_spec.rb b/spec/requests/api/group_labels_spec.rb
index 34533da53dd..1dd90413d35 100644
--- a/spec/requests/api/group_labels_spec.rb
+++ b/spec/requests/api/group_labels_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupLabels do
+RSpec.describe API::GroupLabels, feature_category: :team_planning do
let_it_be(:valid_group_label_title_1) { 'Label foo & bar:subgroup::v.1' }
let_it_be(:valid_group_label_title_1_esc) { ERB::Util.url_encode(valid_group_label_title_1) }
let_it_be(:valid_group_label_title_2) { 'Bar & foo:subgroup::v.2' }
diff --git a/spec/requests/api/group_milestones_spec.rb b/spec/requests/api/group_milestones_spec.rb
index da84e98b905..91f64d02d43 100644
--- a/spec/requests/api/group_milestones_spec.rb
+++ b/spec/requests/api/group_milestones_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupMilestones do
+RSpec.describe API::GroupMilestones, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:project) { create(:project, namespace: group) }
diff --git a/spec/requests/api/group_packages_spec.rb b/spec/requests/api/group_packages_spec.rb
index a2b0b35c76a..0b4f6130132 100644
--- a/spec/requests/api/group_packages_spec.rb
+++ b/spec/requests/api/group_packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupPackages do
+RSpec.describe API::GroupPackages, feature_category: :package_registry do
let_it_be(:group) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, namespace: group, name: 'project A') }
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb
index a07a8ae4292..90b9606ec7b 100644
--- a/spec/requests/api/group_variables_spec.rb
+++ b/spec/requests/api/group_variables_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::GroupVariables do
+RSpec.describe API::GroupVariables, feature_category: :pipeline_authoring do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:variable) { create(:ci_group_variable, group: group) }
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index c94bc1e1bac..12a6553f51a 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Groups do
+RSpec.describe API::Groups, feature_category: :subgroups do
include GroupAPIHelpers
include UploadHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/helm_packages_spec.rb b/spec/requests/api/helm_packages_spec.rb
index 6bd81f64913..584f6e3c7d4 100644
--- a/spec/requests/api/helm_packages_spec.rb
+++ b/spec/requests/api/helm_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::HelmPackages do
+RSpec.describe API::HelmPackages, feature_category: :package_registry do
include_context 'helm api setup'
using RSpec::Parameterized::TableSyntax
@@ -17,6 +17,8 @@ RSpec.describe API::HelmPackages do
let_it_be(:package_file2_2) { create(:helm_package_file, package: package2, file_sha256: 'file2', file_name: 'filename2.tgz', channel: 'test', description: 'hello from test channel') }
let_it_be(:other_package) { create(:npm_package, project: project) }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_helm_user' } }
+
describe 'GET /api/v4/projects/:id/packages/helm/:channel/index.yaml' do
let(:project_id) { project.id }
let(:channel) { 'stable' }
@@ -63,7 +65,6 @@ RSpec.describe API::HelmPackages do
with_them do
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, personal_access_token.token) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
before do
project.update!(visibility: visibility.to_s)
@@ -74,8 +75,6 @@ RSpec.describe API::HelmPackages do
end
context 'with access to package registry for everyone' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
-
before do
project.update!(visibility: Gitlab::VisibilityLevel::PRIVATE)
project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
@@ -152,7 +151,6 @@ RSpec.describe API::HelmPackages do
let(:params) { { chart: temp_file(file_name) } }
let(:file_key) { :chart }
let(:send_rewritten_field) { true }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
subject do
workhorse_finalize(
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index e29e5c31a34..38275ce0057 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
require 'raven/transports/dummy'
require_relative '../../../config/initializers/sentry'
-RSpec.describe API::Helpers do
+RSpec.describe API::Helpers, :enable_admin_mode, feature_category: :authentication_and_authorization do
include API::APIGuard::HelperMethods
include described_class
include TermsHelper
diff --git a/spec/requests/api/import_bitbucket_server_spec.rb b/spec/requests/api/import_bitbucket_server_spec.rb
index 8ab41f49549..7c2df52fdf3 100644
--- a/spec/requests/api/import_bitbucket_server_spec.rb
+++ b/spec/requests/api/import_bitbucket_server_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ImportBitbucketServer do
+RSpec.describe API::ImportBitbucketServer, feature_category: :importers do
let(:base_uri) { "https://test:7990" }
let(:user) { create(:user) }
let(:token) { "asdasd12345" }
diff --git a/spec/requests/api/import_github_spec.rb b/spec/requests/api/import_github_spec.rb
index 4f95295c14d..dce82f1cf37 100644
--- a/spec/requests/api/import_github_spec.rb
+++ b/spec/requests/api/import_github_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ImportGithub do
+RSpec.describe API::ImportGithub, feature_category: :importers do
let(:token) { "asdasd12345" }
let(:provider) { :github }
let(:access_params) { { github_access_token: token } }
diff --git a/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb b/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb
index 8a222a99b34..8d7b462771d 100644
--- a/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb
+++ b/spec/requests/api/integrations/jira_connect/subscriptions_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Integrations::JiraConnect::Subscriptions do
+RSpec.describe API::Integrations::JiraConnect::Subscriptions, feature_category: :integrations do
describe 'POST /integrations/jira_connect/subscriptions' do
subject(:post_subscriptions) { post api('/integrations/jira_connect/subscriptions') }
@@ -20,20 +20,6 @@ RSpec.describe API::Integrations::JiraConnect::Subscriptions do
post api('/integrations/jira_connect/subscriptions', user), params: { jwt: jwt, namespace_path: group.path }
end
- context 'with feature flag disabled' do
- before do
- stub_feature_flags(jira_connect_oauth: false)
- end
-
- let(:jwt) { '123' }
-
- it 'returns 404' do
- post_subscriptions
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
context 'with invalid JWT' do
let(:jwt) { '123' }
diff --git a/spec/requests/api/integrations_spec.rb b/spec/requests/api/integrations_spec.rb
index 1e8061f9606..c35b9bab0ec 100644
--- a/spec/requests/api/integrations_spec.rb
+++ b/spec/requests/api/integrations_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe API::Integrations do
+RSpec.describe API::Integrations, feature_category: :integrations do
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index 32cacfc713c..f9284f21aaa 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Base do
+RSpec.describe API::Internal::Base, feature_category: :authentication_and_authorization do
include GitlabShellHelpers
include APIInternalBaseHelpers
@@ -325,6 +325,28 @@ RSpec.describe API::Internal::Base do
expect(json_response['name']).to eq(user.name)
end
+ context 'when signing key is passed' do
+ it 'does not authenticate user' do
+ key.signing!
+
+ get(api("/internal/discover"), params: { key_id: key.id }, headers: gitlab_shell_internal_api_request_header)
+
+ expect(json_response).to be_nil
+ end
+ end
+
+ context 'when auth-only key is passed' do
+ it 'authenticates user' do
+ key.auth!
+
+ get(api("/internal/discover"), params: { key_id: key.id }, headers: gitlab_shell_internal_api_request_header)
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expect(json_response['name']).to eq(user.name)
+ end
+ end
+
it "finds a user by username" do
get(api("/internal/discover"), params: { username: user.username }, headers: gitlab_shell_internal_api_request_header)
@@ -360,6 +382,30 @@ RSpec.describe API::Internal::Base do
expect(json_response['key'].split[1]).to eq(key.key.split[1])
end
+ context 'when signing key is passed' do
+ it 'does not return the key' do
+ key.signing!
+
+ get(api('/internal/authorized_keys'), params: { key: key.key.split[1] }, headers: gitlab_shell_internal_api_request_header)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+
+ expect(json_response['id']).to be_nil
+ end
+ end
+
+ context 'when auth-only key is passed' do
+ it 'authenticates user' do
+ key.auth!
+
+ get(api('/internal/authorized_keys'), params: { key: key.key.split[1] }, headers: gitlab_shell_internal_api_request_header)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(key.id)
+ expect(json_response['key'].split[1]).to eq(key.key.split[1])
+ end
+ end
+
it 'exposes the comment of the key as a simple identifier of username + hostname' do
get(api('/internal/authorized_keys'), params: { key: key.key.split[1] }, headers: gitlab_shell_internal_api_request_header)
diff --git a/spec/requests/api/internal/container_registry/migration_spec.rb b/spec/requests/api/internal/container_registry/migration_spec.rb
index db2918e65f1..b9258e4627a 100644
--- a/spec/requests/api/internal/container_registry/migration_spec.rb
+++ b/spec/requests/api/internal/container_registry/migration_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::ContainerRegistry::Migration, :aggregate_failures do
+RSpec.describe API::Internal::ContainerRegistry::Migration, :aggregate_failures, feature_category: :database do
let_it_be_with_reload(:repository) { create(:container_repository) }
let(:secret_token) { 'secret_token' }
diff --git a/spec/requests/api/internal/error_tracking_spec.rb b/spec/requests/api/internal/error_tracking_spec.rb
index 4c420eb8505..83012e26138 100644
--- a/spec/requests/api/internal/error_tracking_spec.rb
+++ b/spec/requests/api/internal/error_tracking_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::ErrorTracking do
+RSpec.describe API::Internal::ErrorTracking, feature_category: :error_tracking do
let(:secret_token) { Gitlab::CurrentSettings.error_tracking_access_token }
let(:headers) do
{ ::API::Internal::ErrorTracking::GITLAB_ERROR_TRACKING_TOKEN_HEADER => secret_token }
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index 3c6604cf409..dc631ad7921 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Kubernetes do
+RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_management do
let(:jwt_auth_headers) do
jwt_token = JWT.encode({ 'iss' => Gitlab::Kas::JWT_ISSUER }, Gitlab::Kas.secret, 'HS256')
@@ -103,15 +103,19 @@ RSpec.describe API::Internal::Kubernetes do
expect(response).to have_gitlab_http_status(:bad_request)
end
- it 'tracks events' do
+ it 'tracks events and unique events', :aggregate_failures do
+ request_count = 2
counters = { gitops_sync: 10, k8s_api_proxy_request: 5 }
- unique_counters = { agent_users_using_ci_tunnel: [10] }
+ unique_counters = { agent_users_using_ci_tunnel: [10, 999, 777, 10] }
expected_counters = {
- kubernetes_agent_gitops_sync: counters[:gitops_sync],
- kubernetes_agent_k8s_api_proxy_request: counters[:k8s_api_proxy_request]
+ kubernetes_agent_gitops_sync: request_count * counters[:gitops_sync],
+ kubernetes_agent_k8s_api_proxy_request: request_count * counters[:k8s_api_proxy_request]
}
+ expected_hll_count = unique_counters[:agent_users_using_ci_tunnel].uniq.count
- send_request(params: { counters: counters, unique_counters: unique_counters })
+ request_count.times do
+ send_request(params: { counters: counters, unique_counters: unique_counters })
+ end
expect(Gitlab::UsageDataCounters::KubernetesAgentCounter.totals).to eq(expected_counters)
@@ -121,7 +125,7 @@ RSpec.describe API::Internal::Kubernetes do
event_names: 'agent_users_using_ci_tunnel',
start_date: Date.current, end_date: Date.current + 10
)
- ).to eq(1)
+ ).to eq(expected_hll_count)
end
end
end
diff --git a/spec/requests/api/internal/lfs_spec.rb b/spec/requests/api/internal/lfs_spec.rb
index 9eb48db5bd5..1021c03f736 100644
--- a/spec/requests/api/internal/lfs_spec.rb
+++ b/spec/requests/api/internal/lfs_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Lfs do
+RSpec.describe API::Internal::Lfs, feature_category: :source_code_management do
include GitlabShellHelpers
include APIInternalBaseHelpers
diff --git a/spec/requests/api/internal/mail_room_spec.rb b/spec/requests/api/internal/mail_room_spec.rb
index a0a9c1f9cb3..7baa26e3508 100644
--- a/spec/requests/api/internal/mail_room_spec.rb
+++ b/spec/requests/api/internal/mail_room_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::MailRoom do
+RSpec.describe API::Internal::MailRoom, feature_category: :service_desk do
let(:base_configs) do
{
enabled: true,
diff --git a/spec/requests/api/internal/pages_spec.rb b/spec/requests/api/internal/pages_spec.rb
index 5b970ca605c..56f1089843b 100644
--- a/spec/requests/api/internal/pages_spec.rb
+++ b/spec/requests/api/internal/pages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Pages do
+RSpec.describe API::Internal::Pages, feature_category: :pages do
let(:auth_headers) do
jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
{ Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
diff --git a/spec/requests/api/internal/workhorse_spec.rb b/spec/requests/api/internal/workhorse_spec.rb
index bcf63bf7c2f..99d0ecabbb7 100644
--- a/spec/requests/api/internal/workhorse_spec.rb
+++ b/spec/requests/api/internal/workhorse_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Workhorse, :allow_forgery_protection do
+RSpec.describe API::Internal::Workhorse, :allow_forgery_protection, feature_category: :not_owned do
include WorkhorseHelpers
context '/authorize_upload' do
diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb
index c07d2e11363..9d3ab269ca1 100644
--- a/spec/requests/api/invitations_spec.rb
+++ b/spec/requests/api/invitations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Invitations do
+RSpec.describe API::Invitations, feature_category: :users do
let_it_be(:maintainer) { create(:user, username: 'maintainer_user') }
let_it_be(:maintainer2) { create(:user, username: 'user-with-maintainer-role') }
let_it_be(:developer) { create(:user) }
diff --git a/spec/requests/api/issue_links_spec.rb b/spec/requests/api/issue_links_spec.rb
index 98f72f22cdc..93bf17d72d7 100644
--- a/spec/requests/api/issue_links_spec.rb
+++ b/spec/requests/api/issue_links_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::IssueLinks do
+RSpec.describe API::IssueLinks, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
@@ -189,6 +189,8 @@ RSpec.describe API::IssueLinks do
end
context 'when authenticated' do
+ let_it_be(:target_issue) { create(:issue, project: project) }
+
context 'when issue link does not exist' do
it 'returns 404' do
perform_request(non_existing_record_id, user)
@@ -197,8 +199,6 @@ RSpec.describe API::IssueLinks do
end
end
- let_it_be(:target_issue) { create(:issue, project: project) }
-
context 'when issue link does not belong to the specified issue' do
it 'returns 404' do
other_issue = create(:issue, project: project)
diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb
index 5c06214316b..0641c2135c1 100644
--- a/spec/requests/api/issues/get_group_issues_spec.rb
+++ b/spec/requests/api/issues/get_group_issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Issues do
+RSpec.describe API::Issues, feature_category: :team_planning do
let_it_be(:user2) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
let_it_be(:non_member) { create(:user) }
diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb
index ec6cc060c83..70966d23576 100644
--- a/spec/requests/api/issues/get_project_issues_spec.rb
+++ b/spec/requests/api/issues/get_project_issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Issues do
+RSpec.describe API::Issues, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace) }
let_it_be(:private_mrs_project) do
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index 0e20b2133db..94f0443e14a 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Issues do
+RSpec.describe API::Issues, feature_category: :team_planning do
using RSpec::Parameterized::TableSyntax
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb
index deaf7be96ab..7305da1305a 100644
--- a/spec/requests/api/issues/post_projects_issues_spec.rb
+++ b/spec/requests/api/issues/post_projects_issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Issues do
+RSpec.describe API::Issues, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) do
create(:project, :public, creator_id: user.id, namespace: user.namespace)
diff --git a/spec/requests/api/issues/put_projects_issues_spec.rb b/spec/requests/api/issues/put_projects_issues_spec.rb
index d6c57b460e0..2d7439d65c1 100644
--- a/spec/requests/api/issues/put_projects_issues_spec.rb
+++ b/spec/requests/api/issues/put_projects_issues_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Issues do
+RSpec.describe API::Issues, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:owner) { create(:owner) }
let(:user2) { create(:user) }
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
index 67c3de324dc..d9a0f061156 100644
--- a/spec/requests/api/keys_spec.rb
+++ b/spec/requests/api/keys_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Keys do
+RSpec.describe API::Keys, feature_category: :authentication_and_authorization do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be(:email) { create(:email, user: user) }
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index 97ab90c9776..b5d7d564749 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Labels do
+RSpec.describe API::Labels, feature_category: :team_planning do
def put_labels_api(route_type, user, spec_params, request_params = {})
if route_type == :deprecated
put api("/projects/#{project.id}/labels", user),
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 5d8ed3dd0f5..82b87007a9b 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Lint do
+RSpec.describe API::Lint, feature_category: :pipeline_authoring do
describe 'POST /ci/lint' do
context 'when signup settings are disabled' do
before do
diff --git a/spec/requests/api/markdown_golden_master_spec.rb b/spec/requests/api/markdown_golden_master_spec.rb
index 4fa946de342..1bb5a1d67ae 100644
--- a/spec/requests/api/markdown_golden_master_spec.rb
+++ b/spec/requests/api/markdown_golden_master_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
# See spec/fixtures/markdown/markdown_golden_master_examples.yml for documentation on how this spec works.
-RSpec.describe API::Markdown, 'Golden Master' do
+RSpec.describe API::Markdown, 'Golden Master', feature_category: :team_planning do
markdown_yml_file_path = File.expand_path('../../fixtures/markdown/markdown_golden_master_examples.yml', __dir__)
include_context 'API::Markdown Golden Master shared context', markdown_yml_file_path
end
diff --git a/spec/requests/api/markdown_snapshot_spec.rb b/spec/requests/api/markdown_snapshot_spec.rb
index f2019172a54..866cbcf8ff6 100644
--- a/spec/requests/api/markdown_snapshot_spec.rb
+++ b/spec/requests/api/markdown_snapshot_spec.rb
@@ -4,6 +4,6 @@ require 'spec_helper'
# See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#markdown-snapshot-testing
# for documentation on this spec.
-RSpec.describe API::Markdown, 'Snapshot' do
+RSpec.describe API::Markdown, 'Snapshot', feature_category: :team_planning do
include_context 'with API::Markdown Snapshot shared context'
end
diff --git a/spec/requests/api/markdown_spec.rb b/spec/requests/api/markdown_spec.rb
index 6239ac4e749..db5bbd610fc 100644
--- a/spec/requests/api/markdown_spec.rb
+++ b/spec/requests/api/markdown_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe API::Markdown do
+RSpec.describe API::Markdown, feature_category: :team_planning do
describe "POST /markdown" do
let(:user) {} # No-op. It gets overwritten in the contexts below.
let(:disable_authenticate_markdown_api) { false }
diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb
index ac8c4aacdf2..092eb442f1f 100644
--- a/spec/requests/api/maven_packages_spec.rb
+++ b/spec/requests/api/maven_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::MavenPackages do
+RSpec.describe API::MavenPackages, feature_category: :package_registry do
using RSpec::Parameterized::TableSyntax
include WorkhorseHelpers
@@ -22,7 +22,8 @@ RSpec.describe API::MavenPackages do
let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_maven_user' } }
+
let(:package_name) { 'com/example/my-app' }
let(:headers) { workhorse_headers }
let(:headers_with_token) { headers.merge('Private-Token' => personal_access_token.token) }
@@ -98,8 +99,6 @@ RSpec.describe API::MavenPackages do
context 'with jar file' do
let_it_be(:package_file) { jar_file }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
-
it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
end
end
@@ -900,6 +899,8 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'package workhorse uploads'
context 'event tracking' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_maven_user' } }
+
it_behaves_like 'a package tracking event', described_class.name, 'push_package'
context 'when the package file fails to be created' do
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index 69be574f38a..4eff5e96e9c 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Members do
+RSpec.describe API::Members, feature_category: :subgroups do
let_it_be(:maintainer) { create(:user, username: 'maintainer_user') }
let_it_be(:maintainer2) { create(:user, username: 'user-with-maintainer-role') }
let_it_be(:developer) { create(:user) }
diff --git a/spec/requests/api/merge_request_approvals_spec.rb b/spec/requests/api/merge_request_approvals_spec.rb
index b18f3017e03..a1d6abec97e 100644
--- a/spec/requests/api/merge_request_approvals_spec.rb
+++ b/spec/requests/api/merge_request_approvals_spec.rb
@@ -2,8 +2,10 @@
require 'spec_helper'
-RSpec.describe API::MergeRequestApprovals do
+RSpec.describe API::MergeRequestApprovals, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
+ let_it_be(:user2) { create(:user) }
+ let_it_be(:bot) { create(:user, :project_bot) }
let_it_be(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) }
let_it_be(:approver) { create :user }
let_it_be(:group) { create :group }
@@ -87,4 +89,83 @@ RSpec.describe API::MergeRequestApprovals do
end
end
end
+
+ describe 'PUT :id/merge_requests/:merge_request_iid/reset_approvals' do
+ before do
+ merge_request.approvals.create!(user: user2)
+ create(:project_member, :maintainer, user: bot, source: project)
+ end
+
+ context 'for a bot user' do
+ it 'clears approvals of the merge_request' do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", bot)
+
+ merge_request.reload
+ expect(response).to have_gitlab_http_status(:accepted)
+ expect(merge_request.approvals).to be_empty
+ end
+
+ context 'when bot user approved the merge request' do
+ before do
+ merge_request.approvals.create!(user: bot)
+ end
+
+ it 'clears approvals of the merge_request' do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", bot)
+
+ merge_request.reload
+ expect(response).to have_gitlab_http_status(:accepted)
+ expect(merge_request.approvals).to be_empty
+ end
+ end
+ end
+
+ context 'for users with non-bot roles' do
+ let(:human_user) { create(:user) }
+
+ [:add_owner, :add_maintainer, :add_developer, :add_guest].each do |role_method|
+ it 'returns 401' do
+ project.send(role_method, human_user)
+
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", human_user)
+
+ merge_request.reload
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ expect(merge_request.approvals.pluck(:user_id)).to contain_exactly(user2.id)
+ end
+ end
+ end
+
+ context 'for bot-users from external namespaces' do
+ let_it_be(:external_bot) { create(:user, :project_bot) }
+
+ context 'for external group bot-user' do
+ before do
+ create(:group_member, :maintainer, user: external_bot, source: create(:group))
+ end
+
+ it 'returns 401' do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", external_bot)
+
+ merge_request.reload
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ expect(merge_request.approvals.pluck(:user_id)).to contain_exactly(user2.id)
+ end
+ end
+
+ context 'for external project bot-user' do
+ before do
+ create(:project_member, :maintainer, user: external_bot, source: create(:project))
+ end
+
+ it 'returns 401' do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", external_bot)
+
+ merge_request.reload
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ expect(merge_request.approvals.pluck(:user_id)).to contain_exactly(user2.id)
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb
index caef946273a..4f812e5d8eb 100644
--- a/spec/requests/api/merge_request_diffs_spec.rb
+++ b/spec/requests/api/merge_request_diffs_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe API::MergeRequestDiffs, 'MergeRequestDiffs' do
+RSpec.describe API::MergeRequestDiffs, 'MergeRequestDiffs', feature_category: :source_code_management do
let!(:user) { create(:user) }
let!(:merge_request) { create(:merge_request, importing: true) }
let!(:project) { merge_request.target_project }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index eea223485ce..0b69000ae7e 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -2,14 +2,13 @@
require "spec_helper"
-RSpec.describe API::MergeRequests do
+RSpec.describe API::MergeRequests, feature_category: :source_code_management do
include ProjectForksHelper
let_it_be(:base_time) { Time.now }
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
- let_it_be(:bot) { create(:user, :project_bot) }
let_it_be(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) }
let(:milestone1) { create(:milestone, title: '0.9', project: project) }
@@ -1788,6 +1787,58 @@ RSpec.describe API::MergeRequests do
end
end
+ describe 'GET /projects/:id/merge_requests/:merge_request_iid/diffs' do
+ let_it_be(:merge_request) do
+ create(
+ :merge_request,
+ :simple,
+ author: user,
+ assignees: [user],
+ source_project: project,
+ target_project: project,
+ source_branch: 'markdown',
+ title: "Test",
+ created_at: base_time
+ )
+ end
+
+ it 'returns a 404 when merge_request_iid not found' do
+ get api("/projects/#{project.id}/merge_requests/0/diffs", user)
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns a 404 when merge_request id is used instead of iid' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/diffs", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when merge request author has only guest access' do
+ it_behaves_like 'rejects user from accessing merge request info' do
+ let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/diffs" }
+ end
+ end
+
+ it 'returns the diffs of the merge_request' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/diffs", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.size).to eq(merge_request.diffs.size)
+ end
+
+ context 'when pagination params are present' do
+ it 'returns limited diffs' do
+ get(
+ api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/diffs", user),
+ params: { page: 1, per_page: 1 }
+ )
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.size).to eq(1)
+ end
+ end
+ end
+
describe 'GET /projects/:id/merge_requests/:merge_request_iid/pipelines' do
let_it_be(:merge_request) { create(:merge_request, :simple, author: user, assignees: [user], source_project: project, target_project: project, source_branch: 'markdown', title: "Test", created_at: base_time) }
@@ -3560,71 +3611,6 @@ RSpec.describe API::MergeRequests do
end
end
- describe 'PUT :id/merge_requests/:merge_request_iid/reset_approvals' do
- before do
- merge_request.approvals.create!(user: user2)
- create(:project_member, :maintainer, user: bot, source: project)
- end
-
- context 'when reset_approvals can be performed' do
- it 'clears approvals of the merge_request' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", bot)
-
- merge_request.reload
- expect(response).to have_gitlab_http_status(:accepted)
- expect(merge_request.approvals).to be_empty
- end
-
- it 'for users with bot role' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", bot)
-
- expect(response).to have_gitlab_http_status(:accepted)
- end
-
- context 'for users with non-bot roles' do
- let(:human_user) { create(:user) }
-
- [:add_owner, :add_maintainer, :add_developer, :add_guest].each do |role_method|
- it 'returns 401' do
- project.send(role_method, human_user)
-
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", human_user)
-
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
- end
- end
-
- context 'for bot-users from external namespaces' do
- let_it_be(:external_bot) { create(:user, :project_bot) }
-
- context 'external group bot-user' do
- before do
- create(:group_member, :maintainer, user: external_bot, source: create(:group))
- end
-
- it 'returns 401' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", external_bot)
-
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
- end
-
- context 'external project bot-user' do
- before do
- create(:project_member, :maintainer, user: external_bot, source: create(:project))
- end
-
- it 'returns 401' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/reset_approvals", external_bot)
-
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
- end
- end
- end
- end
-
describe 'Time tracking' do
let!(:issuable) { create(:merge_request, :simple, author: user, assignees: [user], source_project: project, target_project: project, source_branch: 'markdown', title: "Test", created_at: base_time) }
diff --git a/spec/requests/api/metadata_spec.rb b/spec/requests/api/metadata_spec.rb
index 5b6407c689b..b9bdadb01cc 100644
--- a/spec/requests/api/metadata_spec.rb
+++ b/spec/requests/api/metadata_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Metadata do
+RSpec.describe API::Metadata, feature_category: :not_owned do
shared_examples_for 'GET /metadata' do
context 'when unauthenticated' do
it 'returns authentication error' do
diff --git a/spec/requests/api/metrics/dashboard/annotations_spec.rb b/spec/requests/api/metrics/dashboard/annotations_spec.rb
index a09596f167d..7932dd29e4d 100644
--- a/spec/requests/api/metrics/dashboard/annotations_spec.rb
+++ b/spec/requests/api/metrics/dashboard/annotations_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Metrics::Dashboard::Annotations do
+RSpec.describe API::Metrics::Dashboard::Annotations, feature_category: :metrics do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :private, :repository, namespace: user.namespace) }
let_it_be(:environment) { create(:environment, project: project) }
diff --git a/spec/requests/api/metrics/user_starred_dashboards_spec.rb b/spec/requests/api/metrics/user_starred_dashboards_spec.rb
index 7f019e1226a..38d3c0be8b2 100644
--- a/spec/requests/api/metrics/user_starred_dashboards_spec.rb
+++ b/spec/requests/api/metrics/user_starred_dashboards_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Metrics::UserStarredDashboards do
+RSpec.describe API::Metrics::UserStarredDashboards, feature_category: :metrics do
let_it_be(:user) { create(:user) }
let_it_be(:dashboard_yml) { fixture_file('lib/gitlab/metrics/dashboard/sample_dashboard.yml') }
let_it_be(:dashboard) { '.gitlab/dashboards/find&seek.yml' }
diff --git a/spec/requests/api/ml/mlflow_spec.rb b/spec/requests/api/ml/mlflow_spec.rb
index 9448f009742..c1ed7d56ba4 100644
--- a/spec/requests/api/ml/mlflow_spec.rb
+++ b/spec/requests/api/ml/mlflow_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'mime/types'
-RSpec.describe API::Ml::Mlflow do
+RSpec.describe API::Ml::Mlflow, feature_category: :mlops do
include SessionHelpers
include ApiHelpers
include HttpBasicAuthHelpers
@@ -12,12 +12,13 @@ RSpec.describe API::Ml::Mlflow do
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:another_project) { build(:project).tap { |p| p.add_developer(developer) } }
let_it_be(:experiment) do
- create(:ml_experiments, user: project.creator, project: project)
+ create(:ml_experiments, :with_metadata, project: project)
end
let_it_be(:candidate) do
create(:ml_candidates,
- :with_metrics_and_params, user: experiment.user, start_time: 1234, experiment: experiment)
+ :with_metrics_and_params, :with_metadata,
+ user: experiment.user, start_time: 1234, experiment: experiment)
end
let_it_be(:tokens) do
@@ -151,7 +152,17 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => experiment_iid,
'name' => experiment.name,
'lifecycle_stage' => 'active',
- 'artifact_location' => 'not_implemented'
+ 'artifact_location' => 'not_implemented',
+ 'tags' => [
+ {
+ 'key' => experiment.metadata[0].name,
+ 'value' => experiment.metadata[0].value
+ },
+ {
+ 'key' => experiment.metadata[1].name,
+ 'value' => experiment.metadata[1].value
+ }
+ ]
}
})
end
@@ -187,7 +198,17 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => experiment.iid.to_s,
'name' => experiment.name,
'lifecycle_stage' => 'active',
- 'artifact_location' => 'not_implemented'
+ 'artifact_location' => 'not_implemented',
+ 'tags' => [
+ {
+ 'key' => experiment.metadata[0].name,
+ 'value' => experiment.metadata[0].value
+ },
+ {
+ 'key' => experiment.metadata[1].name,
+ 'value' => experiment.metadata[1].value
+ }
+ ]
]
})
end
@@ -220,7 +241,17 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => experiment.iid.to_s,
'name' => experiment_name,
'lifecycle_stage' => 'active',
- 'artifact_location' => 'not_implemented'
+ 'artifact_location' => 'not_implemented',
+ 'tags' => [
+ {
+ 'key' => experiment.metadata[0].name,
+ 'value' => experiment.metadata[0].value
+ },
+ {
+ 'key' => experiment.metadata[1].name,
+ 'value' => experiment.metadata[1].value
+ }
+ ]
}
})
end
@@ -284,10 +315,44 @@ RSpec.describe API::Ml::Mlflow do
end
end
+ describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/experiments/set-experiment-tag' do
+ let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/experiments/set-experiment-tag" }
+ let(:default_params) { { experiment_id: experiment.iid.to_s, key: 'some_key', value: 'value' } }
+ let(:params) { default_params }
+ let(:request) { post api(route), params: params, headers: headers }
+
+ it 'logs the tag', :aggregate_failures do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_empty
+ expect(experiment.reload.metadata.map(&:name)).to include('some_key')
+ end
+
+ describe 'Error Cases' do
+ context 'when tag was already set' do
+ let(:params) { default_params.merge(key: experiment.metadata[0].name) }
+
+ it_behaves_like 'Bad Request'
+ end
+
+ it_behaves_like 'shared error cases'
+ it_behaves_like 'Requires api scope'
+ it_behaves_like 'Bad Request on missing required', [:key, :value]
+ end
+ end
+
describe 'Runs' do
describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/create' do
let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/runs/create" }
- let(:params) { { experiment_id: experiment.iid.to_s, start_time: Time.now.to_i } }
+ let(:params) do
+ {
+ experiment_id: experiment.iid.to_s,
+ start_time: Time.now.to_i,
+ tags: [
+ { key: 'hello', value: 'world' }
+ ]
+ }
+ end
+
let(:request) { post api(route), params: params, headers: headers }
it 'creates the run', :aggregate_failures do
@@ -295,14 +360,18 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => params[:experiment_id],
'user_id' => current_user.id.to_s,
'start_time' => params[:start_time],
- 'status' => "RUNNING",
- 'lifecycle_stage' => "active"
+ 'status' => 'RUNNING',
+ 'lifecycle_stage' => 'active'
}
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('ml/run')
expect(json_response['run']).to include('info' => hash_including(**expected_properties),
- 'data' => { 'metrics' => [], 'params' => [] })
+ 'data' => {
+ 'metrics' => [],
+ 'params' => [],
+ 'tags' => [{ 'key' => 'hello', 'value' => 'world' }]
+ })
end
describe 'Error States' do
@@ -355,6 +424,10 @@ RSpec.describe API::Ml::Mlflow do
'params' => [
{ 'key' => candidate.params[0].name, 'value' => candidate.params[0].value },
{ 'key' => candidate.params[1].name, 'value' => candidate.params[1].value }
+ ],
+ 'tags' => [
+ { 'key' => 'metadata_1', 'value' => 'value1' },
+ { 'key' => 'metadata_2', 'value' => 'value2' }
]
})
end
@@ -454,6 +527,31 @@ RSpec.describe API::Ml::Mlflow do
end
end
+ describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/set-tag' do
+ let(:route) { "/projects/#{project_id}/ml/mlflow/api/2.0/mlflow/runs/set-tag" }
+ let(:default_params) { { run_id: candidate.iid.to_s, key: 'some_key', value: 'value' } }
+ let(:request) { post api(route), params: params, headers: headers }
+
+ it 'logs the tag', :aggregate_failures do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_empty
+ expect(candidate.reload.metadata.map(&:name)).to include('some_key')
+ end
+
+ describe 'Error Cases' do
+ context 'when tag was already logged' do
+ let(:params) { default_params.tap { |p| p[:key] = candidate.metadata[0].name } }
+
+ it_behaves_like 'Bad Request'
+ end
+
+ it_behaves_like 'shared error cases'
+ it_behaves_like 'Requires api scope'
+ it_behaves_like 'run_id param error cases'
+ it_behaves_like 'Bad Request on missing required', [:key, :value]
+ end
+ end
+
describe 'POST /projects/:id/ml/mlflow/api/2.0/mlflow/runs/log-batch' do
let(:candidate2) do
create(:ml_candidates, user: experiment.user, start_time: 1234, experiment: experiment)
@@ -467,7 +565,8 @@ RSpec.describe API::Ml::Mlflow do
{ key: 'mae', value: 2.5, timestamp: 1552550804 },
{ key: 'rmse', value: 2.7, timestamp: 1552550804 }
],
- params: [{ key: 'model_class', value: 'LogisticRegression' }]
+ params: [{ key: 'model_class', value: 'LogisticRegression' }],
+ tags: [{ key: 'tag1', value: 'tag.value.1' }]
}
end
@@ -477,6 +576,7 @@ RSpec.describe API::Ml::Mlflow do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_empty
expect(candidate2.params.size).to eq(1)
+ expect(candidate2.metadata.size).to eq(1)
expect(candidate2.metrics.size).to eq(2)
end
@@ -493,6 +593,19 @@ RSpec.describe API::Ml::Mlflow do
end
end
+ context 'when tag was already logged' do
+ let(:params) do
+ default_params.tap { |p| p[:tags] = [{ key: 'tag1', value: 'a' }, { key: 'tag1', value: 'b' }] }
+ end
+
+ it 'logs only 1', :aggregate_failures do
+ candidate.metadata.reload
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(candidate2.metadata.size).to eq(1)
+ end
+ end
+
describe 'Error Cases' do
context 'when required metric key is missing' do
let(:params) { default_params.tap { |p| p[:metrics] = [p[:metrics][0].delete(:key)] } }
diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb
index ab39c29653f..30616964371 100644
--- a/spec/requests/api/namespaces_spec.rb
+++ b/spec/requests/api/namespaces_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Namespaces do
+RSpec.describe API::Namespaces, feature_category: :subgroups do
let_it_be(:admin) { create(:admin) }
let_it_be(:user) { create(:user) }
let_it_be(:group1) { create(:group, name: 'group.one') }
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 89abb28140a..c2d9db1e6fb 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Notes do
+RSpec.describe API::Notes, feature_category: :team_planning do
let!(:user) { create(:user) }
let!(:project) { create(:project, :public) }
let(:private_user) { create(:user) }
@@ -203,6 +203,51 @@ RSpec.describe API::Notes do
end
end
end
+
+ context 'without notes widget' do
+ let(:request_body) { 'Hi!' }
+ let(:params) { { body: request_body } }
+ let(:request_path) { "/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes" }
+
+ before do
+ stub_const('WorkItems::Type::BASE_TYPES', { issue: { name: 'NoNotesWidget', enum_value: 0 } })
+ stub_const('WorkItems::Type::WIDGETS_FOR_TYPE', { issue: [::WorkItems::Widgets::Description] })
+ end
+
+ it 'does not fetch notes' do
+ get api(request_path, private_user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'does not fetch specific note' do
+ get api("#{request_path}/#{cross_reference_note.id}", private_user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'does not create note' do
+ post api(request_path, private_user), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'does not update note' do
+ put api("#{request_path}/#{cross_reference_note.id}", private_user), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'does not run quick actions' do
+ params[:body] = "/spend 1h"
+
+ expect do
+ post api("#{request_path}/#{cross_reference_note.id}", private_user), params: params
+ end.to not_change { Note.system.count }.and(not_change { Note.where(system: false).count })
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
end
diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb
index b5551c21738..2a80dc4bbe9 100644
--- a/spec/requests/api/notification_settings_spec.rb
+++ b/spec/requests/api/notification_settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::NotificationSettings do
+RSpec.describe API::NotificationSettings, feature_category: :team_planning do
let(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:project) { create(:project, :public, creator_id: user.id, namespace: group) }
diff --git a/spec/requests/api/npm_instance_packages_spec.rb b/spec/requests/api/npm_instance_packages_spec.rb
index 698885ddcf4..dcd2e4ae677 100644
--- a/spec/requests/api/npm_instance_packages_spec.rb
+++ b/spec/requests/api/npm_instance_packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::NpmInstancePackages do
+RSpec.describe API::NpmInstancePackages, feature_category: :package_registry do
# We need to create a subgroup with the same name as the hosting group.
# It has to be created first to exhibit this bug: https://gitlab.com/gitlab-org/gitlab/-/issues/321958
let_it_be(:another_namespace) { create(:group, :public) }
@@ -33,4 +33,16 @@ RSpec.describe API::NpmInstancePackages do
let(:url) { api("/packages/npm/-/package/#{package_name}/dist-tags/#{tag_name}") }
end
end
+
+ describe 'POST /api/v4/packages/npm/-/npm/v1/security/advisories/bulk' do
+ it_behaves_like 'handling audit request', path: 'advisories/bulk', scope: :instance do
+ let(:url) { api('/packages/npm/-/npm/v1/security/advisories/bulk') }
+ end
+ end
+
+ describe 'POST /api/v4/packages/npm/-/npm/v1/security/audits/quick' do
+ it_behaves_like 'handling audit request', path: 'audits/quick', scope: :instance do
+ let(:url) { api('/packages/npm/-/npm/v1/security/audits/quick') }
+ end
+ end
end
diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb
index 373327787a2..c62c0849776 100644
--- a/spec/requests/api/npm_project_packages_spec.rb
+++ b/spec/requests/api/npm_project_packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::NpmProjectPackages do
+RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do
include_context 'npm api setup'
shared_examples 'accept get request on private project with access to package registry for everyone' do
@@ -42,8 +42,19 @@ RSpec.describe API::NpmProjectPackages do
end
end
+ describe 'POST /api/v4/projects/:id/packages/npm/-/npm/v1/security/advisories/bulk' do
+ it_behaves_like 'handling audit request', path: 'advisories/bulk', scope: :project do
+ let(:url) { api("/projects/#{project.id}/packages/npm/-/npm/v1/security/advisories/bulk") }
+ end
+ end
+
+ describe 'POST /api/v4/projects/:id/packages/npm/-/npm/v1/security/audits/quick' do
+ it_behaves_like 'handling audit request', path: 'audits/quick', scope: :project do
+ let(:url) { api("/projects/#{project.id}/packages/npm/-/npm/v1/security/audits/quick") }
+ end
+ end
+
describe 'GET /api/v4/projects/:id/packages/npm/*package_name/-/*file_name' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
let(:package_file) { package.package_files.first }
let(:headers) { {} }
@@ -203,7 +214,7 @@ RSpec.describe API::NpmProjectPackages do
let_it_be(:version) { '1.2.3' }
let(:params) { upload_params(package_name: package_name, package_version: version) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_npm_user' } }
shared_examples 'handling upload with different authentications' do
context 'with access token' do
diff --git a/spec/requests/api/nuget_group_packages_spec.rb b/spec/requests/api/nuget_group_packages_spec.rb
index c1375288809..9de612f7bc7 100644
--- a/spec/requests/api/nuget_group_packages_spec.rb
+++ b/spec/requests/api/nuget_group_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::NugetGroupPackages do
+RSpec.describe API::NugetGroupPackages, feature_category: :package_registry do
include_context 'nuget api setup'
using RSpec::Parameterized::TableSyntax
@@ -12,6 +12,7 @@ RSpec.describe API::NugetGroupPackages do
let_it_be(:deploy_token) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token, group: group) }
+ let(:snowplow_gitlab_standard_context) { { namespace: project.group, property: 'i_package_nuget_user' } }
let(:target_type) { 'groups' }
shared_examples 'handling all endpoints' do
@@ -46,7 +47,6 @@ RSpec.describe API::NugetGroupPackages do
let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token, group: subgroup) }
let(:target) { subgroup }
- let(:snowplow_gitlab_standard_context) { { namespace: subgroup } }
it_behaves_like 'handling all endpoints'
@@ -58,7 +58,7 @@ RSpec.describe API::NugetGroupPackages do
context 'a group' do
let(:target) { group }
- let(:snowplow_gitlab_standard_context) { { namespace: group } }
+ let(:snowplow_gitlab_standard_context) { { namespace: target, property: 'i_package_nuget_user' } }
it_behaves_like 'handling all endpoints'
diff --git a/spec/requests/api/nuget_project_packages_spec.rb b/spec/requests/api/nuget_project_packages_spec.rb
index f608f296295..1e0d35ad451 100644
--- a/spec/requests/api/nuget_project_packages_spec.rb
+++ b/spec/requests/api/nuget_project_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::NugetProjectPackages do
+RSpec.describe API::NugetProjectPackages, feature_category: :package_registry do
include_context 'nuget api setup'
using RSpec::Parameterized::TableSyntax
@@ -9,38 +9,62 @@ RSpec.describe API::NugetProjectPackages do
let_it_be_with_reload(:project) { create(:project, :public) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
+ let_it_be(:package_name) { 'Dummy.Package' }
let(:target) { project }
let(:target_type) { 'projects' }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_nuget_user' } }
- describe 'GET /api/v4/projects/:id/packages/nuget' do
- it_behaves_like 'handling nuget service requests' do
- let(:url) { "/projects/#{target.id}/packages/nuget/index.json" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+ shared_examples 'accept get request on private project with access to package registry for everyone' do
+ subject { get api(url) }
+
+ before do
+ update_visibility_to(Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
end
+
+ it_behaves_like 'returning response status', :ok
+ end
+
+ describe 'GET /api/v4/projects/:id/packages/nuget' do
+ let(:url) { "/projects/#{target.id}/packages/nuget/index.json" }
+
+ it_behaves_like 'handling nuget service requests'
+
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/nuget/metadata/*package_name/index' do
- it_behaves_like 'handling nuget metadata requests with package name' do
- let(:url) { "/projects/#{target.id}/packages/nuget/metadata/#{package_name}/index.json" }
+ let(:url) { "/projects/#{target.id}/packages/nuget/metadata/#{package_name}/index.json" }
+
+ it_behaves_like 'handling nuget metadata requests with package name'
+
+ it_behaves_like 'accept get request on private project with access to package registry for everyone' do
+ let_it_be(:packages) { create_list(:nuget_package, 5, :with_metadatum, name: package_name, project: project) }
end
end
describe 'GET /api/v4/projects/:id/packages/nuget/metadata/*package_name/*package_version' do
- it_behaves_like 'handling nuget metadata requests with package name and package version' do
- let(:url) { "/projects/#{target.id}/packages/nuget/metadata/#{package_name}/#{package.version}.json" }
+ let(:url) { "/projects/#{target.id}/packages/nuget/metadata/#{package_name}/#{package.version}.json" }
+
+ it_behaves_like 'handling nuget metadata requests with package name and package version'
+
+ it_behaves_like 'accept get request on private project with access to package registry for everyone' do
+ let_it_be(:package) { create(:nuget_package, :with_metadatum, name: package_name, project: project) }
end
end
describe 'GET /api/v4/projects/:id/packages/nuget/query' do
- it_behaves_like 'handling nuget search requests' do
- let(:url) { "/projects/#{target.id}/packages/nuget/query?#{query_parameters.to_query}" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+ let(:url) { "/projects/#{target.id}/packages/nuget/query?#{query_parameters.to_query}" }
+
+ it_behaves_like 'handling nuget search requests'
+
+ it_behaves_like 'accept get request on private project with access to package registry for everyone' do
+ let_it_be(:query_parameters) { { q: 'query', take: 5, skip: 0, prerelease: true } }
end
end
describe 'GET /api/v4/projects/:id/packages/nuget/download/*package_name/index' do
- let_it_be(:package_name) { 'Dummy.Package' }
let_it_be(:packages) { create_list(:nuget_package, 5, name: package_name, project: project) }
let(:url) { "/projects/#{target.id}/packages/nuget/download/#{package_name}/index.json" }
@@ -88,10 +112,11 @@ RSpec.describe API::NugetProjectPackages do
it_behaves_like 'rejects nuget access with unknown target id'
it_behaves_like 'rejects nuget access with invalid target id'
+
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/nuget/download/*package_name/*package_version/*package_filename' do
- let_it_be(:package_name) { 'Dummy.Package' }
let_it_be(:package) { create(:nuget_package, :with_symbol_package, project: project, name: package_name) }
let(:format) { 'nupkg' }
@@ -124,7 +149,6 @@ RSpec.describe API::NugetProjectPackages do
with_them do
let(:token) { user_token ? personal_access_token.token : 'wrong' }
let(:headers) { user_role == :anonymous ? {} : basic_auth_header(user.username, token) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
subject { get api(url), headers: headers }
@@ -134,6 +158,8 @@ RSpec.describe API::NugetProjectPackages do
it_behaves_like params[:shared_examples_name], params[:user_role], params[:expected_status], params[:member]
end
+
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
it_behaves_like 'deploy token for package GET requests' do
diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb
index f07dcfcccd6..b29f1e9e661 100644
--- a/spec/requests/api/oauth_tokens_spec.rb
+++ b/spec/requests/api/oauth_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'OAuth tokens' do
+RSpec.describe 'OAuth tokens', feature_category: :authentication_and_authorization do
include HttpBasicAuthHelpers
context 'Resource Owner Password Credentials' do
@@ -85,8 +85,6 @@ RSpec.describe 'OAuth tokens' do
context 'with invalid credentials' do
it 'does not create an access token' do
- pending 'Enable this example after https://github.com/doorkeeper-gem/doorkeeper/pull/1488 is merged and released'
-
user = create(:user)
request_oauth_token(user, basic_auth_header(client.uid, 'invalid secret'))
diff --git a/spec/requests/api/package_files_spec.rb b/spec/requests/api/package_files_spec.rb
index 01c7ef1476f..f47dca387ef 100644
--- a/spec/requests/api/package_files_spec.rb
+++ b/spec/requests/api/package_files_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::PackageFiles do
+RSpec.describe API::PackageFiles, feature_category: :package_registry do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:package) { create(:maven_package, project: project) }
diff --git a/spec/requests/api/pages/internal_access_spec.rb b/spec/requests/api/pages/internal_access_spec.rb
index 4ac47f17b7e..fdc25ecdcd3 100644
--- a/spec/requests/api/pages/internal_access_spec.rb
+++ b/spec/requests/api/pages/internal_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Internal Project Pages Access" do
+RSpec.describe "Internal Project Pages Access", feature_category: :pages do
using RSpec::Parameterized::TableSyntax
include AccessMatchers
diff --git a/spec/requests/api/pages/pages_spec.rb b/spec/requests/api/pages/pages_spec.rb
index 4a94bf90205..c426f2a433c 100644
--- a/spec/requests/api/pages/pages_spec.rb
+++ b/spec/requests/api/pages/pages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Pages do
+RSpec.describe API::Pages, feature_category: :pages do
let_it_be(:project) { create(:project, path: 'my.project', pages_https_only: false) }
let_it_be(:admin) { create(:admin) }
let_it_be(:user) { create(:user) }
diff --git a/spec/requests/api/pages/private_access_spec.rb b/spec/requests/api/pages/private_access_spec.rb
index c1c0e406508..5cc1b8f9a69 100644
--- a/spec/requests/api/pages/private_access_spec.rb
+++ b/spec/requests/api/pages/private_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Private Project Pages Access" do
+RSpec.describe "Private Project Pages Access", feature_category: :pages do
using RSpec::Parameterized::TableSyntax
include AccessMatchers
diff --git a/spec/requests/api/pages/public_access_spec.rb b/spec/requests/api/pages/public_access_spec.rb
index c45b3a4c55e..1137f91f4b0 100644
--- a/spec/requests/api/pages/public_access_spec.rb
+++ b/spec/requests/api/pages/public_access_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe "Public Project Pages Access" do
+RSpec.describe "Public Project Pages Access", feature_category: :pages do
using RSpec::Parameterized::TableSyntax
include AccessMatchers
diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb
index 8ef4e899193..65fcf9e006a 100644
--- a/spec/requests/api/pages_domains_spec.rb
+++ b/spec/requests/api/pages_domains_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::PagesDomains do
+RSpec.describe API::PagesDomains, feature_category: :pages do
let_it_be(:project) { create(:project, path: 'my.project', pages_https_only: false) }
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/performance_bar_spec.rb b/spec/requests/api/performance_bar_spec.rb
index a4dbb3d17b8..9fbe34914c5 100644
--- a/spec/requests/api/performance_bar_spec.rb
+++ b/spec/requests/api/performance_bar_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe 'Performance Bar for API requests', :request_store, :clean_gitlab_redis_cache do
+RSpec.describe 'Performance Bar for API requests', :request_store, :clean_gitlab_redis_cache,
+feature_category: :metrics do
context 'with user that has access to the performance bar' do
let_it_be(:admin) { create(:admin) }
diff --git a/spec/requests/api/personal_access_tokens/self_information_spec.rb b/spec/requests/api/personal_access_tokens/self_information_spec.rb
index bdfac3ed14f..4a3c0ad8904 100644
--- a/spec/requests/api/personal_access_tokens/self_information_spec.rb
+++ b/spec/requests/api/personal_access_tokens/self_information_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::PersonalAccessTokens::SelfInformation do
+RSpec.describe API::PersonalAccessTokens::SelfInformation, feature_category: :authentication_and_authorization do
let(:path) { '/personal_access_tokens/self' }
let(:token) { create(:personal_access_token, user: current_user) }
diff --git a/spec/requests/api/personal_access_tokens_spec.rb b/spec/requests/api/personal_access_tokens_spec.rb
index 1fa2ad6ebfa..32adc7ebd61 100644
--- a/spec/requests/api/personal_access_tokens_spec.rb
+++ b/spec/requests/api/personal_access_tokens_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::PersonalAccessTokens do
+RSpec.describe API::PersonalAccessTokens, feature_category: :authentication_and_authorization do
let_it_be(:path) { '/personal_access_tokens' }
describe 'GET /personal_access_tokens' do
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index 2ff4cd72f1e..cc399d25429 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -43,6 +43,7 @@ itself: # project
- storage_version
- topic_list
- updated_at
+ - mirror_branch_regex
remapped_attributes:
avatar: avatar_url
build_allow_git_fetch: build_git_strategy
@@ -124,10 +125,6 @@ project_feature:
- created_at
- metrics_dashboard_access_level
- package_registry_access_level
- - monitor_access_level
- - infrastructure_access_level
- - feature_flags_access_level
- - environments_access_level
- project_id
- updated_at
computed_attributes:
@@ -163,6 +160,7 @@ project_setting:
- suggested_reviewers_enabled
- jitsu_key
- mirror_branch_regex
+ - allow_pipeline_trigger_approve_deployment
build_service_desk_setting: # service_desk_setting
unexposed_attributes:
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index 4c7da78f0d4..895192252da 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectClusters do
+RSpec.describe API::ProjectClusters, feature_category: :kubernetes_management do
include KubernetesHelpers
let_it_be(:maintainer_user) { create(:user) }
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index 52ec06d76a9..a2e1a1c1721 100644
--- a/spec/requests/api/project_container_repositories_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectContainerRepositories do
+RSpec.describe API::ProjectContainerRepositories, feature_category: :package_registry do
include ExclusiveLeaseHelpers
let_it_be(:project) { create(:project, :private) }
@@ -33,7 +33,10 @@ RSpec.describe API::ProjectContainerRepositories do
let(:method) { :get }
let(:params) { {} }
- let(:snowplow_gitlab_standard_context) { { user: api_user, project: project, namespace: project.namespace } }
+ let(:snowplow_gitlab_standard_context) do
+ { user: api_user, project: project, namespace: project.namespace,
+ property: 'i_package_container_user' }
+ end
before_all do
project.add_maintainer(maintainer)
@@ -144,20 +147,6 @@ RSpec.describe API::ProjectContainerRepositories do
expect(response).to have_gitlab_http_status(:accepted)
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 removal of repository' do
- expect(DeleteContainerRepositoryWorker).to receive(:perform_async)
- .with(maintainer.id, root_repository.id)
- expect { subject }.to change { root_repository.reload.status }.from(nil).to('delete_scheduled')
-
- expect(response).to have_gitlab_http_status(:accepted)
- end
- end
end
end
end
@@ -414,6 +403,9 @@ RSpec.describe API::ProjectContainerRepositories do
context 'for developer', :snowplow do
let(:api_user) { developer }
+ let(:service_ping_context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'i_package_container_user').to_h]
+ end
context 'when there are multiple tags' do
before do
@@ -427,7 +419,10 @@ RSpec.describe API::ProjectContainerRepositories do
subject
expect(response).to have_gitlab_http_status(:ok)
- expect_snowplow_event(category: described_class.name, action: 'delete_tag', project: project, user: api_user, namespace: project.namespace)
+ expect_snowplow_event(category: described_class.name, action: 'delete_tag', project: project,
+ user: api_user, namespace: project.namespace.reload,
+ label: 'redis_hll_counters.user_packages.user_packages_total_unique_counts_monthly',
+ property: 'i_package_container_user', context: service_ping_context)
end
end
@@ -443,7 +438,10 @@ RSpec.describe API::ProjectContainerRepositories do
subject
expect(response).to have_gitlab_http_status(:ok)
- expect_snowplow_event(category: described_class.name, action: 'delete_tag', project: project, user: api_user, namespace: project.namespace)
+ expect_snowplow_event(category: described_class.name, action: 'delete_tag', project: project,
+ user: api_user, namespace: project.namespace.reload,
+ label: 'redis_hll_counters.user_packages.user_packages_total_unique_counts_monthly',
+ property: 'i_package_container_user', context: service_ping_context)
end
end
end
diff --git a/spec/requests/api/project_debian_distributions_spec.rb b/spec/requests/api/project_debian_distributions_spec.rb
index 2b993f24046..9807f177c5d 100644
--- a/spec/requests/api/project_debian_distributions_spec.rb
+++ b/spec/requests/api/project_debian_distributions_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::ProjectDebianDistributions do
+RSpec.describe API::ProjectDebianDistributions, feature_category: :package_registry do
include HttpBasicAuthHelpers
include WorkhorseHelpers
@@ -23,13 +23,13 @@ RSpec.describe API::ProjectDebianDistributions do
describe 'GET projects/:id/debian_distributions' do
let(:url) { "/projects/#{container.id}/debian_distributions" }
- it_behaves_like 'Debian distributions read endpoint', 'GET', :success, /^\[{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/
+ it_behaves_like 'Debian distributions read endpoint', 'GET', :success, /^\[{.*"codename":"existing-codename",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/
end
describe 'GET projects/:id/debian_distributions/:codename' do
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
- it_behaves_like 'Debian distributions read endpoint', 'GET', :success, /^{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/
+ it_behaves_like 'Debian distributions read endpoint', 'GET', :success, /^{.*"codename":"existing-codename",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/
end
describe 'GET projects/:id/debian_distributions/:codename/key.asc' do
@@ -56,7 +56,7 @@ RSpec.describe API::ProjectDebianDistributions do
let(:method) { :delete }
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
- it_behaves_like 'Debian distributions maintainer write endpoint', 'DELETE', :success, /^{\"message\":\"202 Accepted\"}$/
+ it_behaves_like 'Debian distributions maintainer write endpoint', 'DELETE', :success, /^{"message":"202 Accepted"}$/
context 'when destroy fails' do
before do
diff --git a/spec/requests/api/project_events_spec.rb b/spec/requests/api/project_events_spec.rb
index f3e592f9796..69d8eb76cf3 100644
--- a/spec/requests/api/project_events_spec.rb
+++ b/spec/requests/api/project_events_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectEvents do
+RSpec.describe API::ProjectEvents, feature_category: :users do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:private_project) { create(:project, :private, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/project_export_spec.rb b/spec/requests/api/project_export_spec.rb
index d74fd82ca09..fdd76c63069 100644
--- a/spec/requests/api/project_export_spec.rb
+++ b/spec/requests/api/project_export_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectExport, :clean_gitlab_redis_cache do
+RSpec.describe API::ProjectExport, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:project) { create(:project) }
let_it_be(:project_none) { create(:project) }
let_it_be(:project_started) { create(:project) }
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 2d925620a91..8e5e9d847ea 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectHooks, 'ProjectHooks' do
+RSpec.describe API::ProjectHooks, 'ProjectHooks', feature_category: :integrations do
let_it_be(:user) { create(:user) }
let_it_be(:user3) { create(:user) }
let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb
index 05fe55b06a1..027c61bb9e1 100644
--- a/spec/requests/api/project_import_spec.rb
+++ b/spec/requests/api/project_import_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectImport, :aggregate_failures do
+RSpec.describe API::ProjectImport, :aggregate_failures, feature_category: :importers do
include WorkhorseHelpers
include AfterNextHelpers
@@ -44,7 +44,7 @@ RSpec.describe API::ProjectImport, :aggregate_failures do
it_behaves_like 'requires authentication'
- it 'executes a limited number of queries' do
+ it 'executes a limited number of queries', :use_clean_rails_redis_caching do
control_count = ActiveRecord::QueryRecorder.new { subject }.count
expect(control_count).to be <= 111
@@ -126,13 +126,31 @@ RSpec.describe API::ProjectImport, :aggregate_failures do
end
end
- it 'schedules an import at the user namespace level' do
- stub_import(user.namespace)
- params[:path] = 'test-import2'
+ context 'when namespace not set' do
+ it 'schedules an import at the user namespace level' do
+ stub_import(user.namespace)
+ params[:path] = 'test-import2'
- subject
+ subject
- expect(response).to have_gitlab_http_status(:created)
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ context 'when current user is a bot user' do
+ let(:user) { create(:user, :project_bot) }
+
+ it 'does not schedule an import' do
+ expect_any_instance_of(ProjectImportState).not_to receive(:schedule)
+
+ params[:namespace] = nil
+ params[:path] = 'test-import3'
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq("Namespace is not valid")
+ end
+ end
end
it 'does not schedule an import for a namespace that does not exist' do
@@ -161,6 +179,20 @@ RSpec.describe API::ProjectImport, :aggregate_failures do
expect(json_response['message']).to eq('404 Namespace Not Found')
end
+ context 'when passed in namespace is a bot user namespace' do
+ let(:user) { create(:user, :project_bot) }
+
+ it 'does not schedule an import' do
+ expect_any_instance_of(ProjectImportState).not_to receive(:schedule)
+ params[:namespace] = user.namespace.full_path
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq("Namespace is not valid")
+ end
+ end
+
context 'if user uploads no valid file' do
let(:file) { 'README.md' }
diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb
index 8294ca143d3..9d722e4a445 100644
--- a/spec/requests/api/project_milestones_spec.rb
+++ b/spec/requests/api/project_milestones_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectMilestones do
+RSpec.describe API::ProjectMilestones, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:project) { create(:project, namespace: user.namespace) }
let_it_be(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
diff --git a/spec/requests/api/project_packages_spec.rb b/spec/requests/api/project_packages_spec.rb
index 00d295b3490..d3adef85f8d 100644
--- a/spec/requests/api/project_packages_spec.rb
+++ b/spec/requests/api/project_packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectPackages do
+RSpec.describe API::ProjectPackages, feature_category: :package_registry do
let_it_be(:project) { create(:project, :public) }
let(:user) { create(:user) }
@@ -350,6 +350,16 @@ RSpec.describe API::ProjectPackages do
end
end
end
+
+ context 'when package has no default status' do
+ let!(:package1) { create(:npm_package, :error, project: project) }
+
+ it 'returns 404' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
describe 'DELETE /projects/:id/packages/:package_id' do
diff --git a/spec/requests/api/project_repository_storage_moves_spec.rb b/spec/requests/api/project_repository_storage_moves_spec.rb
index 5b272121233..96ed3042d00 100644
--- a/spec/requests/api/project_repository_storage_moves_spec.rb
+++ b/spec/requests/api/project_repository_storage_moves_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectRepositoryStorageMoves do
+RSpec.describe API::ProjectRepositoryStorageMoves, feature_category: :gitaly do
it_behaves_like 'repository_storage_moves API', 'projects' do
let_it_be(:container) { create(:project, :repository) }
let_it_be(:storage_move) { create(:project_repository_storage_move, :scheduled, container: container) }
diff --git a/spec/requests/api/project_snapshots_spec.rb b/spec/requests/api/project_snapshots_spec.rb
index bf78ff56206..5d3c596e605 100644
--- a/spec/requests/api/project_snapshots_spec.rb
+++ b/spec/requests/api/project_snapshots_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectSnapshots do
+RSpec.describe API::ProjectSnapshots, feature_category: :source_code_management do
include WorkhorseHelpers
let(:project) { create(:project) }
@@ -21,7 +21,7 @@ RSpec.describe API::ProjectSnapshots do
expect(type).to eq('git-snapshot')
expect(params).to eq(
'GitalyServer' => {
- 'features' => { 'gitaly-feature-foobar' => 'true' },
+ 'call_metadata' => { 'gitaly-feature-foobar' => 'true' },
'address' => Gitlab::GitalyClient.address(repository.project.repository_storage),
'token' => Gitlab::GitalyClient.token(repository.project.repository_storage)
},
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 1d255f7c1d8..568486deb7f 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectSnippets do
+RSpec.describe API::ProjectSnippets, feature_category: :source_code_management do
include SnippetHelpers
let_it_be(:project) { create(:project, :public) }
diff --git a/spec/requests/api/project_statistics_spec.rb b/spec/requests/api/project_statistics_spec.rb
index d314af0746a..39ead8cc573 100644
--- a/spec/requests/api/project_statistics_spec.rb
+++ b/spec/requests/api/project_statistics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectStatistics do
+RSpec.describe API::ProjectStatistics, feature_category: :source_code_management do
let_it_be(:reporter) { create(:user) }
let_it_be(:public_project) { create(:project, :public) }
diff --git a/spec/requests/api/project_templates_spec.rb b/spec/requests/api/project_templates_spec.rb
index 87d70a87f42..38d6a05a104 100644
--- a/spec/requests/api/project_templates_spec.rb
+++ b/spec/requests/api/project_templates_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProjectTemplates do
+RSpec.describe API::ProjectTemplates, feature_category: :source_code_management do
let_it_be(:public_project) { create(:project, :public, :repository, create_templates: :merge_request, path: 'path.with.dot') }
let_it_be(:private_project) { create(:project, :private, :repository, create_templates: :issue) }
let_it_be(:developer) { create(:user) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 3831e8e1dfe..6e8168c0ee1 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.shared_examples 'languages and percentages JSON response' do
+RSpec.shared_examples 'languages and percentages JSON response', feature_category: :projects do
let(:expected_languages) { project.repository.languages.to_h { |language| language.values_at(:label, :value) } }
before do
@@ -231,14 +231,16 @@ RSpec.describe API::Projects do
include_examples 'includes container_registry_access_level'
end
- it 'includes releases_access_level', :aggregate_failures do
- project.project_feature.update!(releases_access_level: ProjectFeature::DISABLED)
-
+ it 'includes various project feature fields', :aggregate_failures do
get api('/projects', user)
project_response = json_response.find { |p| p['id'] == project.id }
expect(response).to have_gitlab_http_status(:ok)
- expect(project_response['releases_access_level']).to eq('disabled')
+ expect(project_response['releases_access_level']).to eq('enabled')
+ expect(project_response['environments_access_level']).to eq('enabled')
+ expect(project_response['feature_flags_access_level']).to eq('enabled')
+ expect(project_response['infrastructure_access_level']).to eq('enabled')
+ expect(project_response['monitor_access_level']).to eq('enabled')
end
context 'when some projects are in a group' do
@@ -1192,6 +1194,10 @@ RSpec.describe API::Projects do
attrs[:container_registry_access_level] = 'private'
attrs[:security_and_compliance_access_level] = 'private'
attrs[:releases_access_level] = 'disabled'
+ attrs[:environments_access_level] = 'disabled'
+ attrs[:feature_flags_access_level] = 'disabled'
+ attrs[:infrastructure_access_level] = 'disabled'
+ attrs[:monitor_access_level] = 'disabled'
end
post api('/projects', user), params: project
@@ -1201,7 +1207,8 @@ RSpec.describe API::Projects do
project.each_pair do |k, v|
next if %i[
has_external_issue_tracker has_external_wiki issues_enabled merge_requests_enabled wiki_enabled storage_version
- container_registry_access_level releases_access_level
+ container_registry_access_level releases_access_level environments_access_level feature_flags_access_level
+ infrastructure_access_level monitor_access_level
].include?(k)
expect(json_response[k.to_s]).to eq(v)
@@ -1217,6 +1224,10 @@ RSpec.describe API::Projects do
expect(project.project_feature.container_registry_access_level).to eq(ProjectFeature::PRIVATE)
expect(project.project_feature.security_and_compliance_access_level).to eq(ProjectFeature::PRIVATE)
expect(project.project_feature.releases_access_level).to eq(ProjectFeature::DISABLED)
+ expect(project.project_feature.environments_access_level).to eq(ProjectFeature::DISABLED)
+ expect(project.project_feature.feature_flags_access_level).to eq(ProjectFeature::DISABLED)
+ expect(project.project_feature.infrastructure_access_level).to eq(ProjectFeature::DISABLED)
+ expect(project.project_feature.monitor_access_level).to eq(ProjectFeature::DISABLED)
end
it 'assigns container_registry_enabled to project', :aggregate_failures do
@@ -2356,6 +2367,10 @@ RSpec.describe API::Projects do
expect(json_response['operations_access_level']).to be_present
expect(json_response['security_and_compliance_access_level']).to be_present
expect(json_response['releases_access_level']).to be_present
+ expect(json_response['environments_access_level']).to be_present
+ expect(json_response['feature_flags_access_level']).to be_present
+ expect(json_response['infrastructure_access_level']).to be_present
+ expect(json_response['monitor_access_level']).to be_present
end
it 'exposes all necessary attributes' do
@@ -2426,6 +2441,10 @@ RSpec.describe API::Projects do
expect(json_response['operations_access_level']).to be_present
expect(json_response['security_and_compliance_access_level']).to be_present
expect(json_response['releases_access_level']).to be_present
+ expect(json_response['environments_access_level']).to be_present
+ expect(json_response['feature_flags_access_level']).to be_present
+ expect(json_response['infrastructure_access_level']).to be_present
+ expect(json_response['monitor_access_level']).to be_present
expect(json_response).to have_key('emails_disabled')
expect(json_response['resolve_outdated_diff_discussions']).to eq(project.resolve_outdated_diff_discussions)
expect(json_response['remove_source_branch_after_merge']).to be_truthy
@@ -3410,12 +3429,14 @@ RSpec.describe API::Projects do
expect(Project.find_by(path: project[:path]).analytics_access_level).to eq(ProjectFeature::PRIVATE)
end
- it 'sets releases_access_level', :aggregate_failures do
- put api("/projects/#{project.id}", user), params: { releases_access_level: 'private' }
+ %i(releases_access_level environments_access_level feature_flags_access_level infrastructure_access_level monitor_access_level).each do |field|
+ it "sets #{field}", :aggregate_failures do
+ put api("/projects/#{project.id}", user), params: { field => 'private' }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['releases_access_level']).to eq('private')
- expect(Project.find_by(path: project[:path]).releases_access_level).to eq(ProjectFeature::PRIVATE)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response[field.to_s]).to eq('private')
+ expect(Project.find_by(path: project[:path]).public_send(field)).to eq(ProjectFeature::PRIVATE)
+ end
end
it 'returns 400 when nothing sent' do
@@ -4687,6 +4708,7 @@ RSpec.describe API::Projects do
end
end
end
+
describe 'PUT /projects/:id/transfer' do
context 'when authenticated as owner' do
let(:group) { create :group }
diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb
index b46859a0e70..8e8a25a8dc2 100644
--- a/spec/requests/api/protected_branches_spec.rb
+++ b/spec/requests/api/protected_branches_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProtectedBranches do
+RSpec.describe API::ProtectedBranches, feature_category: :source_code_management do
let_it_be_with_reload(:project) { create(:project, :repository) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:guest) { create(:user) }
diff --git a/spec/requests/api/protected_tags_spec.rb b/spec/requests/api/protected_tags_spec.rb
index f1db39ac204..5b128d4ec9e 100644
--- a/spec/requests/api/protected_tags_spec.rb
+++ b/spec/requests/api/protected_tags_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ProtectedTags do
+RSpec.describe API::ProtectedTags, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:project2) { create(:project, path: 'project2', namespace: user.namespace) }
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index 12091158a02..59d93cd48e3 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::PypiPackages do
+RSpec.describe API::PypiPackages, feature_category: :package_registry do
include WorkhorseHelpers
include PackagesManagerApiSpecHelpers
include HttpBasicAuthHelpers
@@ -14,6 +14,7 @@ RSpec.describe API::PypiPackages do
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:job) { create(:ci_build, :running, user: user, project: project) }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
let(:headers) { {} }
@@ -25,7 +26,7 @@ RSpec.describe API::PypiPackages do
describe 'GET /api/v4/groups/:id/-/packages/pypi/simple' do
let(:url) { "/groups/#{group.id}/-/packages/pypi/simple" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
it_behaves_like 'pypi simple index API endpoint'
it_behaves_like 'rejects PyPI access with unknown group id'
@@ -63,7 +64,7 @@ RSpec.describe API::PypiPackages do
describe 'GET /api/v4/projects/:id/packages/pypi/simple' do
let(:package_name) { package.name }
let(:url) { "/projects/#{project.id}/packages/pypi/simple" }
- let(:snowplow_gitlab_standard_context) { { project: nil, namespace: group } }
+ let(:snowplow_gitlab_standard_context) { { project: nil, namespace: group, property: 'i_package_pypi_user' } }
it_behaves_like 'pypi simple index API endpoint'
it_behaves_like 'rejects PyPI access with unknown project id'
@@ -81,13 +82,13 @@ RSpec.describe API::PypiPackages do
context 'simple package API endpoint' do
let_it_be(:package) { create(:pypi_package, project: project) }
+ let(:snowplow_gitlab_standard_context) { { project: nil, namespace: group, property: 'i_package_pypi_user' } }
subject { get api(url), headers: headers }
describe 'GET /api/v4/groups/:id/-/packages/pypi/simple/:package_name' do
let(:package_name) { package.name }
let(:url) { "/groups/#{group.id}/-/packages/pypi/simple/#{package_name}" }
- let(:snowplow_gitlab_standard_context) { { project: nil, namespace: group } }
it_behaves_like 'pypi simple API endpoint'
it_behaves_like 'rejects PyPI access with unknown group id'
@@ -125,7 +126,7 @@ RSpec.describe API::PypiPackages do
describe 'GET /api/v4/projects/:id/packages/pypi/simple/:package_name' do
let(:package_name) { package.name }
let(:url) { "/projects/#{project.id}/packages/pypi/simple/#{package_name}" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_pypi_user' } }
it_behaves_like 'pypi simple API endpoint'
it_behaves_like 'rejects PyPI access with unknown project id'
@@ -202,7 +203,7 @@ RSpec.describe API::PypiPackages do
let(:base_params) { { requires_python: requires_python, version: '1.0.0', name: 'sample-project', sha256_digest: '1' * 64, md5_digest: '1' * 32 } }
let(:params) { base_params.merge(content: temp_file(file_name)) }
let(:send_rewritten_field) { true }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_pypi_user' } }
subject do
workhorse_finalize(
@@ -366,7 +367,6 @@ RSpec.describe API::PypiPackages do
describe 'GET /api/v4/groups/:id/-/packages/pypi/files/:sha256/*file_identifier' do
let(:url) { "/groups/#{group.id}/-/packages/pypi/files/#{package.package_files.first.file_sha256}/#{package_name}-1.0.0.tar.gz" }
- let(:snowplow_gitlab_standard_context) { {} }
it_behaves_like 'pypi file download endpoint'
it_behaves_like 'rejects PyPI access with unknown group id'
@@ -375,7 +375,6 @@ RSpec.describe API::PypiPackages do
describe 'GET /api/v4/projects/:id/packages/pypi/files/:sha256/*file_identifier' do
let(:url) { "/projects/#{project.id}/packages/pypi/files/#{package.package_files.first.file_sha256}/#{package_name}-1.0.0.tar.gz" }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
it_behaves_like 'pypi file download endpoint'
it_behaves_like 'rejects PyPI access with unknown project id'
diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb
index 38166c5ce97..6036960c43c 100644
--- a/spec/requests/api/release/links_spec.rb
+++ b/spec/requests/api/release/links_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Release::Links do
+RSpec.describe API::Release::Links, feature_category: :release_orchestration do
let(:project) { create(:project, :repository, :private) }
let(:maintainer) { create(:user) }
let(:developer) { create(:user) }
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index 754b77af60e..a1aff9a6b1c 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Releases do
+RSpec.describe API::Releases, feature_category: :release_orchestration do
let(:project) { create(:project, :repository, :private) }
let(:maintainer) { create(:user) }
let(:reporter) { create(:user) }
diff --git a/spec/requests/api/remote_mirrors_spec.rb b/spec/requests/api/remote_mirrors_spec.rb
index 338647224e0..3da1760e319 100644
--- a/spec/requests/api/remote_mirrors_spec.rb
+++ b/spec/requests/api/remote_mirrors_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::RemoteMirrors do
+RSpec.describe API::RemoteMirrors, feature_category: :source_code_management do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, :remote_mirror) }
let_it_be(:developer) { create(:user) { |u| project.add_developer(u) } }
@@ -90,7 +90,9 @@ RSpec.describe API::RemoteMirrors do
}
expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']['url']).to eq(["is blocked: Only allowed schemes are ssh, git, http, https"])
+ expect(json_response['message']['url']).to match_array(
+ ["is blocked: Only allowed schemes are http, https, ssh, git"]
+ )
end
end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 3c22f918af5..393ada1da4f 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'mime/types'
-RSpec.describe API::Repositories do
+RSpec.describe API::Repositories, feature_category: :source_code_management do
include RepoHelpers
include WorkhorseHelpers
include ProjectForksHelper
@@ -300,7 +300,7 @@ RSpec.describe API::Repositories do
type, params = workhorse_send_data
expect(type).to eq('git-archive')
- expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\.tar.gz/)
+ expect(params['ArchivePath']).to match(/#{project.path}-[^.]+\.tar.gz/)
expect(response.parsed_body).to be_empty
end
@@ -312,7 +312,7 @@ RSpec.describe API::Repositories do
type, params = workhorse_send_data
expect(type).to eq('git-archive')
- expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\.zip/)
+ expect(params['ArchivePath']).to match(/#{project.path}-[^.]+\.zip/)
end
it 'returns the repository archive archive.tar.bz2' do
@@ -323,7 +323,7 @@ RSpec.describe API::Repositories do
type, params = workhorse_send_data
expect(type).to eq('git-archive')
- expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\.tar.bz2/)
+ expect(params['ArchivePath']).to match(/#{project.path}-[^.]+\.tar.bz2/)
end
context 'when sha does not exist' do
@@ -342,7 +342,7 @@ RSpec.describe API::Repositories do
type, params = workhorse_send_data
expect(type).to eq('git-archive')
- expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\-#{path}\.tar.gz/)
+ expect(params['ArchivePath']).to match(/#{project.path}-[^.]+-#{path}\.tar.gz/)
end
it 'rate limits user when thresholds hit' do
diff --git a/spec/requests/api/resource_access_tokens_spec.rb b/spec/requests/api/resource_access_tokens_spec.rb
index 24efac3128d..6a89e9a56df 100644
--- a/spec/requests/api/resource_access_tokens_spec.rb
+++ b/spec/requests/api/resource_access_tokens_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe API::ResourceAccessTokens do
+RSpec.describe API::ResourceAccessTokens, feature_category: :authentication_and_authorization do
let_it_be(:user) { create(:user) }
let_it_be(:user_non_priviledged) { create(:user) }
diff --git a/spec/requests/api/resource_label_events_spec.rb b/spec/requests/api/resource_label_events_spec.rb
index a4a70d89812..1adffea17b7 100644
--- a/spec/requests/api/resource_label_events_spec.rb
+++ b/spec/requests/api/resource_label_events_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ResourceLabelEvents do
+RSpec.describe API::ResourceLabelEvents, feature_category: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :public, namespace: user.namespace) }
let_it_be(:label) { create(:label, project: project) }
diff --git a/spec/requests/api/resource_milestone_events_spec.rb b/spec/requests/api/resource_milestone_events_spec.rb
index 5c81c2180d7..fe991533c85 100644
--- a/spec/requests/api/resource_milestone_events_spec.rb
+++ b/spec/requests/api/resource_milestone_events_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::ResourceMilestoneEvents do
+RSpec.describe API::ResourceMilestoneEvents, feature_category: :team_planning do
let!(:user) { create(:user) }
let!(:project) { create(:project, :public, namespace: user.namespace) }
let!(:milestone) { create(:milestone, project: project) }
diff --git a/spec/requests/api/rpm_project_packages_spec.rb b/spec/requests/api/rpm_project_packages_spec.rb
index 68511795c94..515970f86a1 100644
--- a/spec/requests/api/rpm_project_packages_spec.rb
+++ b/spec/requests/api/rpm_project_packages_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
-RSpec.describe API::RpmProjectPackages do
+RSpec.describe API::RpmProjectPackages, feature_category: :package_registry do
include HttpBasicAuthHelpers
include WorkhorseHelpers
@@ -136,7 +136,7 @@ RSpec.describe API::RpmProjectPackages do
end
describe 'GET /api/v4/projects/:id/packages/rpm/:package_file_id/:filename' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: group } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: group, property: 'i_package_rpm_user' } }
let(:url) { "/projects/#{project.id}/packages/rpm/#{package_file_id}/#{package_name}" }
subject { get api(url), headers: headers }
@@ -148,7 +148,10 @@ RSpec.describe API::RpmProjectPackages do
end
describe 'POST /api/v4/projects/:project_id/packages/rpm' do
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: group, user: user } }
+ let(:snowplow_gitlab_standard_context) do
+ { project: project, namespace: group, user: user, property: 'i_package_rpm_user' }
+ end
+
let(:url) { "/projects/#{project.id}/packages/rpm" }
let(:file_upload) { fixture_file_upload('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.x86_64.rpm') }
@@ -213,6 +216,19 @@ RSpec.describe API::RpmProjectPackages do
expect(response.body).to match(/File is too large/)
end
end
+
+ context 'when filelists.xml file size too large' do
+ before do
+ create(:rpm_repository_file, :filelists, size: 21.megabytes, project: project)
+ end
+
+ it 'returns an error' do
+ upload_file(params: { file: file_upload }, request_headers: headers)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response.body).to match(/Repository packages limit exceeded/)
+ end
+ end
end
def upload_file(params: {}, request_headers: headers)
diff --git a/spec/requests/api/rubygem_packages_spec.rb b/spec/requests/api/rubygem_packages_spec.rb
index a7d461781b8..6f048fa57a8 100644
--- a/spec/requests/api/rubygem_packages_spec.rb
+++ b/spec/requests/api/rubygem_packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::RubygemPackages do
+RSpec.describe API::RubygemPackages, feature_category: :package_registry do
include PackagesManagerApiSpecHelpers
include WorkhorseHelpers
using RSpec::Parameterized::TableSyntax
@@ -15,7 +15,7 @@ RSpec.describe API::RubygemPackages do
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
let_it_be(:headers) { {} }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user, property: 'i_package_rubygems_user' } }
let(:tokens) do
{
@@ -164,7 +164,7 @@ RSpec.describe API::RubygemPackages do
with_them do
let(:token) { valid_token ? tokens[token_type] : 'invalid-token123' }
let(:headers) { user_role == :anonymous ? {} : { 'HTTP_AUTHORIZATION' => token } }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, property: 'i_package_rubygems_user' } }
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value(visibility.to_s))
@@ -323,7 +323,7 @@ RSpec.describe API::RubygemPackages do
let(:token) { valid_token ? tokens[token_type] : 'invalid-token123' }
let(:user_headers) { user_role == :anonymous ? {} : { 'HTTP_AUTHORIZATION' => token } }
let(:headers) { user_headers.merge(workhorse_headers) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: snowplow_user } }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: snowplow_user, property: 'i_package_rubygems_user' } }
let(:snowplow_user) do
case token_type
when :deploy_token
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index 60acf6b71dd..430d3b7d187 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Search do
+RSpec.describe API::Search, feature_category: :global_search do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:project, reload: true) { create(:project, :wiki_repo, :public, name: 'awesome project', group: group) }
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 3a9b2d02af5..e93ef52ef03 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
+RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting, feature_category: :not_owned do
let(:user) { create(:user) }
let_it_be(:admin) { create(:admin) }
@@ -25,6 +25,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
expect(json_response['secret_detection_token_revocation_url']).to be_nil
expect(json_response['secret_detection_revocation_token_types_url']).to be_nil
expect(json_response['sourcegraph_public_only']).to be_truthy
+ expect(json_response['default_preferred_language']).to be_a String
expect(json_response['default_project_visibility']).to be_a String
expect(json_response['default_snippet_visibility']).to be_a String
expect(json_response['default_group_visibility']).to be_a String
@@ -55,12 +56,15 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
expect(json_response['group_runner_token_expiration_interval']).to be_nil
expect(json_response['project_runner_token_expiration_interval']).to be_nil
expect(json_response['max_export_size']).to eq(0)
+ expect(json_response['max_terraform_state_size_bytes']).to eq(0)
expect(json_response['pipeline_limit_per_project_user_sha']).to eq(0)
expect(json_response['delete_inactive_projects']).to be(false)
expect(json_response['inactive_projects_delete_after_months']).to eq(2)
expect(json_response['inactive_projects_min_size_mb']).to eq(0)
expect(json_response['inactive_projects_send_warning_email_after_months']).to eq(1)
expect(json_response['can_create_group']).to eq(true)
+ expect(json_response['jira_connect_application_key']).to eq(nil)
+ expect(json_response['jira_connect_proxy_url']).to eq(nil)
end
end
@@ -146,6 +150,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
mailgun_events_enabled: true,
mailgun_signing_key: 'MAILGUN_SIGNING_KEY',
max_export_size: 6,
+ max_terraform_state_size_bytes: 1_000,
disabled_oauth_sign_in_sources: 'unknown',
import_sources: 'github,bitbucket',
wiki_page_max_content_bytes: 12345,
@@ -158,7 +163,10 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
inactive_projects_delete_after_months: 24,
inactive_projects_min_size_mb: 10,
inactive_projects_send_warning_email_after_months: 12,
- can_create_group: false
+ can_create_group: false,
+ jira_connect_application_key: '123',
+ jira_connect_proxy_url: 'http://example.com',
+ bulk_import_enabled: false
}
expect(response).to have_gitlab_http_status(:ok)
@@ -207,6 +215,7 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
expect(json_response['mailgun_events_enabled']).to be(true)
expect(json_response['mailgun_signing_key']).to eq('MAILGUN_SIGNING_KEY')
expect(json_response['max_export_size']).to eq(6)
+ expect(json_response['max_terraform_state_size_bytes']).to eq(1_000)
expect(json_response['disabled_oauth_sign_in_sources']).to eq([])
expect(json_response['import_sources']).to match_array(%w(github bitbucket))
expect(json_response['wiki_page_max_content_bytes']).to eq(12345)
@@ -220,6 +229,9 @@ RSpec.describe API::Settings, 'Settings', :do_not_mock_admin_mode_setting do
expect(json_response['inactive_projects_min_size_mb']).to eq(10)
expect(json_response['inactive_projects_send_warning_email_after_months']).to eq(12)
expect(json_response['can_create_group']).to eq(false)
+ expect(json_response['jira_connect_application_key']).to eq('123')
+ expect(json_response['jira_connect_proxy_url']).to eq('http://example.com')
+ expect(json_response['bulk_import_enabled']).to be(false)
end
end
diff --git a/spec/requests/api/sidekiq_metrics_spec.rb b/spec/requests/api/sidekiq_metrics_spec.rb
index 302d824e650..1085df97cc7 100644
--- a/spec/requests/api/sidekiq_metrics_spec.rb
+++ b/spec/requests/api/sidekiq_metrics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::SidekiqMetrics do
+RSpec.describe API::SidekiqMetrics, feature_category: :not_owned do
let(:admin) { create(:user, :admin) }
describe 'GET sidekiq/*' do
diff --git a/spec/requests/api/snippet_repository_storage_moves_spec.rb b/spec/requests/api/snippet_repository_storage_moves_spec.rb
index 40d01500ac1..6081531aee9 100644
--- a/spec/requests/api/snippet_repository_storage_moves_spec.rb
+++ b/spec/requests/api/snippet_repository_storage_moves_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::SnippetRepositoryStorageMoves do
+RSpec.describe API::SnippetRepositoryStorageMoves, feature_category: :gitaly do
it_behaves_like 'repository_storage_moves API', 'snippets' do
let_it_be(:container) { create(:snippet, :repository).tap { |snippet| snippet.create_repository } }
let_it_be(:storage_move) { create(:snippet_repository_storage_move, :scheduled, container: container) }
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 9408d1cc248..dd0da0cb887 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Snippets, factory_default: :keep do
+RSpec.describe API::Snippets, factory_default: :keep, feature_category: :source_code_management do
include SnippetHelpers
let_it_be(:admin) { create(:user, :admin) }
diff --git a/spec/requests/api/statistics_spec.rb b/spec/requests/api/statistics_spec.rb
index baffb2792e9..85fed48a077 100644
--- a/spec/requests/api/statistics_spec.rb
+++ b/spec/requests/api/statistics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Statistics, 'Statistics' do
+RSpec.describe API::Statistics, 'Statistics', feature_category: :devops_reports do
include ProjectForksHelper
tables_to_analyze = %w[
projects
diff --git a/spec/requests/api/submodules_spec.rb b/spec/requests/api/submodules_spec.rb
index 9840476ca27..7b041ab7c4b 100644
--- a/spec/requests/api/submodules_spec.rb
+++ b/spec/requests/api/submodules_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Submodules do
+RSpec.describe API::Submodules, feature_category: :source_code_management do
let(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace) }
let(:guest) { create(:user) { |u| project.add_guest(u) } }
diff --git a/spec/requests/api/suggestions_spec.rb b/spec/requests/api/suggestions_spec.rb
index dfc5d169af6..93b2435c601 100644
--- a/spec/requests/api/suggestions_spec.rb
+++ b/spec/requests/api/suggestions_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Suggestions do
+RSpec.describe API::Suggestions, feature_category: :code_review do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 0f1dbea2e73..51edf4b3b3e 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::SystemHooks do
+RSpec.describe API::SystemHooks, feature_category: :integrations do
let_it_be(:non_admin) { create(:user) }
let_it_be(:admin) { create(:admin) }
let_it_be_with_refind(:hook) { create(:system_hook, url: "http://example.com") }
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index 3f2ca2a0938..b02c7135b7b 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Tags do
+RSpec.describe API::Tags, feature_category: :source_code_management do
let(:user) { create(:user) }
let(:guest) { create(:user).tap { |u| project.add_guest(u) } }
let(:project) { create(:project, :repository, creator: user, path: 'my.project') }
@@ -479,4 +479,60 @@ RSpec.describe API::Tags do
end
end
end
+
+ describe 'GET /projects/:id/repository/tags/:tag_name/signature' do
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let(:project_id) { project.id }
+ let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}/signature" }
+
+ context 'when tag does not exist' do
+ let(:tag_name) { 'unknown' }
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(route, current_user) }
+ let(:message) { '404 Tag Not Found' }
+ end
+ end
+
+ context 'unsigned tag' do
+ let(:tag_name) { 'v1.1.0' }
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(route, current_user) }
+ let(:message) { '404 Signature Not Found' }
+ end
+ end
+
+ context 'x509 signed tag' do
+ let(:tag_name) { 'v1.1.1' }
+ let(:tag) { project.repository.find_tag(tag_name) }
+ let(:signature) { tag.signature }
+ let(:x509_certificate) { signature.x509_certificate }
+ let(:x509_issuer) { x509_certificate.x509_issuer }
+
+ it 'returns correct JSON' do
+ get api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq(
+ 'signature_type' => 'X509',
+ 'verification_status' => signature.verification_status.to_s,
+ 'x509_certificate' => {
+ 'id' => x509_certificate.id,
+ 'subject' => x509_certificate.subject,
+ 'subject_key_identifier' => x509_certificate.subject_key_identifier,
+ 'email' => x509_certificate.email,
+ 'serial_number' => x509_certificate.serial_number,
+ 'certificate_status' => x509_certificate.certificate_status,
+ 'x509_issuer' => {
+ 'id' => x509_issuer.id,
+ 'subject' => x509_issuer.subject,
+ 'subject_key_identifier' => x509_issuer.subject_key_identifier,
+ 'crl_url' => x509_issuer.crl_url
+ }
+ }
+ )
+ end
+ end
+ end
end
diff --git a/spec/requests/api/task_completion_status_spec.rb b/spec/requests/api/task_completion_status_spec.rb
index 97ce858ba12..c46d6954da3 100644
--- a/spec/requests/api/task_completion_status_spec.rb
+++ b/spec/requests/api/task_completion_status_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'task completion status response' do
+RSpec.describe 'task completion status response', features: :team_planning do
let_it_be(:user) { create(:user) }
let_it_be(:project) do
create(:project, :public, creator_id: user.id, namespace: user.namespace)
@@ -10,44 +10,44 @@ RSpec.describe 'task completion status response' do
shared_examples 'taskable completion status provider' do |path|
samples = [
- {
- description: '',
- expected_count: 0,
- expected_completed_count: 0
- },
- {
- description: 'Lorem ipsum',
- expected_count: 0,
- expected_completed_count: 0
- },
- {
- description: %{- [ ] task 1
+ {
+ description: '',
+ expected_count: 0,
+ expected_completed_count: 0
+ },
+ {
+ description: 'Lorem ipsum',
+ expected_count: 0,
+ expected_completed_count: 0
+ },
+ {
+ description: %{- [ ] task 1
- [x] task 2 },
- expected_count: 2,
- expected_completed_count: 1
- },
- {
- description: %{- [ ] task 1
+ expected_count: 2,
+ expected_completed_count: 1
+ },
+ {
+ description: %{- [ ] task 1
- [ ] task 2 },
- expected_count: 2,
- expected_completed_count: 0
- },
- {
- description: %{- [x] task 1
+ expected_count: 2,
+ expected_completed_count: 0
+ },
+ {
+ description: %{- [x] task 1
- [x] task 2 },
- expected_count: 2,
- expected_completed_count: 2
- },
- {
- description: %{- [ ] task 1},
- expected_count: 1,
- expected_completed_count: 0
- },
- {
- description: %{- [x] task 1},
- expected_count: 1,
- expected_completed_count: 1
- }
+ expected_count: 2,
+ expected_completed_count: 2
+ },
+ {
+ description: %{- [ ] task 1},
+ expected_count: 1,
+ expected_completed_count: 0
+ },
+ {
+ description: %{- [x] task 1},
+ expected_count: 1,
+ expected_completed_count: 1
+ }
]
samples.each do |sample_data|
context "with a description of #{sample_data[:description].inspect}" do
diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb
index adb37c62dc3..8782c3cba4b 100644
--- a/spec/requests/api/templates_spec.rb
+++ b/spec/requests/api/templates_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Templates do
+RSpec.describe API::Templates, feature_category: :source_code_management do
context 'the Template Entity' do
before do
get api('/templates/gitignores/Ruby')
diff --git a/spec/requests/api/terraform/modules/v1/packages_spec.rb b/spec/requests/api/terraform/modules/v1/packages_spec.rb
index ae61017f5bb..2bd7cb027aa 100644
--- a/spec/requests/api/terraform/modules/v1/packages_spec.rb
+++ b/spec/requests/api/terraform/modules/v1/packages_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Terraform::Modules::V1::Packages do
+RSpec.describe API::Terraform::Modules::V1::Packages, feature_category: :package_registry do
include PackagesManagerApiSpecHelpers
include WorkhorseHelpers
using RSpec::Parameterized::TableSyntax
@@ -418,7 +418,8 @@ RSpec.describe API::Terraform::Modules::V1::Packages do
{
project: project,
user: user_role == :anonymous ? nil : user,
- namespace: project.namespace
+ namespace: project.namespace,
+ property: 'i_package_terraform_module_user'
}
end
@@ -583,7 +584,10 @@ RSpec.describe API::Terraform::Modules::V1::Packages do
with_them do
let(:user_headers) { user_role == :anonymous ? {} : { token_header => token } }
let(:headers) { user_headers.merge(workhorse_headers) }
- let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: snowplow_user } }
+ let(:snowplow_gitlab_standard_context) do
+ { project: project, namespace: project.namespace, user: snowplow_user, property: 'i_package_terraform_module_user' }
+ end
+
let(:snowplow_user) do
case token_type
when :deploy_token
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index 38b08b4e214..fd34345d814 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -2,20 +2,22 @@
require 'spec_helper'
-RSpec.describe API::Terraform::State, :snowplow do
+RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructure_as_code do
include HttpBasicAuthHelpers
let_it_be(:project) { create(:project) }
let_it_be(:developer) { create(:user, developer_projects: [project]) }
let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) }
- let!(:state) { create(:terraform_state, :with_version, project: project) }
-
let(:current_user) { maintainer }
let(:auth_header) { user_basic_auth_header(current_user) }
let(:project_id) { project.id }
- let(:state_name) { state.name }
+
+ let(:state_name) { "some-state" }
let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}" }
+ let!(:state) do
+ create(:terraform_state, :with_version, project: project, name: URI.decode_www_form_component(state_name))
+ end
before do
stub_terraform_state_object_storage
@@ -91,15 +93,35 @@ RSpec.describe API::Terraform::State, :snowplow do
end
end
- context 'personal acceess token authentication' do
+ shared_examples 'can access terraform state' do
+ it 'returns terraform state of a project of given state name' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(state.reload.latest_file.read)
+ end
+ end
+
+ context 'personal access token authentication' do
context 'with maintainer permissions' do
let(:current_user) { maintainer }
- it 'returns terraform state belonging to a project of given state name' do
- request
+ where(given_state_name: %w[test-state test.state test%2Ffoo])
+ with_them do
+ it_behaves_like 'can access terraform state' do
+ let(:state_name) { given_state_name }
+ end
+ end
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.body).to eq(state.reload.latest_file.read)
+ context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
+ let(:state_name) { 'state-name-with-dot' }
+ let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}.tfstate" }
+
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it_behaves_like 'can access terraform state'
end
context 'for a project that does not exist' do
@@ -112,18 +134,23 @@ RSpec.describe API::Terraform::State, :snowplow do
end
end
+ context 'with invalid state name' do
+ let(:state_name) { 'foo/bar' }
+
+ it 'returns a 404 error' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
it_behaves_like 'cannot access a state that is scheduled for deletion'
end
context 'with developer permissions' do
let(:current_user) { developer }
- it 'returns terraform state belonging to a project of given state name' do
- request
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.body).to eq(state.reload.latest_file.read)
- end
+ it_behaves_like 'can access terraform state'
end
end
@@ -133,12 +160,7 @@ RSpec.describe API::Terraform::State, :snowplow do
context 'with maintainer permissions' do
let(:job) { create(:ci_build, status: :running, project: project, user: maintainer) }
- it 'returns terraform state belonging to a project of given state name' do
- request
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.body).to eq(state.reload.latest_file.read)
- end
+ it_behaves_like 'can access terraform state'
it 'returns unauthorized if the the job is not running' do
job.update!(status: :failed)
@@ -161,12 +183,7 @@ RSpec.describe API::Terraform::State, :snowplow do
context 'with developer permissions' do
let(:job) { create(:ci_build, status: :running, project: project, user: developer) }
- it 'returns terraform state belonging to a project of given state name' do
- request
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.body).to eq(state.reload.latest_file.read)
- end
+ it_behaves_like 'can access terraform state'
end
end
end
@@ -182,11 +199,26 @@ RSpec.describe API::Terraform::State, :snowplow do
context 'with maintainer permissions' do
let(:current_user) { maintainer }
- it 'updates the state' do
- expect { request }.to change { Terraform::State.count }.by(0)
+ where(given_state_name: %w[test-state test.state test%2Ffoo])
+ with_them do
+ let(:state_name) { given_state_name }
- expect(response).to have_gitlab_http_status(:ok)
- expect(Gitlab::Json.parse(response.body)).to be_empty
+ it 'updates the state' do
+ expect { request }.to change { Terraform::State.count }.by(0)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Gitlab::Json.parse(response.body)).to be_empty
+ end
+ end
+
+ context 'with invalid state name' do
+ let(:state_name) { 'foo/bar' }
+
+ it 'returns a 404 error' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
context 'when serial already exists' do
@@ -224,16 +256,39 @@ RSpec.describe API::Terraform::State, :snowplow do
end
context 'when there is no terraform state of a given name' do
- let(:state_name) { 'example2' }
+ let(:non_existing_state_name) { 'non-existing-state' }
+ let(:non_existing_state_path) { "/projects/#{project_id}/terraform/state/#{non_existing_state_name}" }
+
+ subject(:request) { post api(non_existing_state_path), headers: auth_header, as: :json, params: params }
context 'with maintainer permissions' do
let(:current_user) { maintainer }
- it 'creates a new state' do
- expect { request }.to change { Terraform::State.count }.by(1)
+ where(given_state_name: %w[test-state test.state test%2Ffoo])
+ with_them do
+ let(:state_name) { given_state_name }
- expect(response).to have_gitlab_http_status(:ok)
- expect(Gitlab::Json.parse(response.body)).to be_empty
+ it 'creates a new state' do
+ expect { request }.to change { Terraform::State.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Gitlab::Json.parse(response.body)).to be_empty
+ end
+ end
+
+ context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
+ let(:non_existing_state_name) { 'state-name-with-dot.tfstate' }
+
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it 'strips characters after the dot' do
+ expect { request }.to change { Terraform::State.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Terraform::State.last.name).to eq('state-name-with-dot')
+ end
end
end
@@ -269,6 +324,48 @@ RSpec.describe API::Terraform::State, :snowplow do
expect(state.reload_latest_version.build).to eq(job)
end
end
+
+ describe 'response depending on the max allowed state size' do
+ let(:current_user) { maintainer }
+
+ before do
+ stub_application_setting(max_terraform_state_size_bytes: max_allowed_state_size)
+
+ request
+ end
+
+ context 'when the max allowed state size is unlimited (set as 0)' do
+ let(:max_allowed_state_size) { 0 }
+
+ it 'returns a success response' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the max allowed state size is greater than the request state size' do
+ let(:max_allowed_state_size) { params.to_json.size + 1 }
+
+ it 'returns a success response' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the max allowed state size is equal to the request state size' do
+ let(:max_allowed_state_size) { params.to_json.size }
+
+ it 'returns a success response' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the max allowed state size is less than the request state size' do
+ let(:max_allowed_state_size) { params.to_json.size - 1 }
+
+ it "returns a 'payload too large' response" do
+ expect(response).to have_gitlab_http_status(:payload_too_large)
+ end
+ end
+ end
end
describe 'DELETE /projects/:id/terraform/state/:name' do
@@ -276,11 +373,8 @@ RSpec.describe API::Terraform::State, :snowplow do
it_behaves_like 'endpoint with unique user tracking'
- context 'with maintainer permissions' do
- let(:current_user) { maintainer }
- let(:deletion_service) { instance_double(Terraform::States::TriggerDestroyService) }
-
- it 'schedules the state for deletion and returns empty body' do
+ shared_examples 'schedules the state for deletion' do
+ it 'returns empty body' do
expect(Terraform::States::TriggerDestroyService).to receive(:new).and_return(deletion_service)
expect(deletion_service).to receive(:execute).once
@@ -289,6 +383,40 @@ RSpec.describe API::Terraform::State, :snowplow do
expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Json.parse(response.body)).to be_empty
end
+ end
+
+ context 'with maintainer permissions' do
+ let(:current_user) { maintainer }
+ let(:deletion_service) { instance_double(Terraform::States::TriggerDestroyService) }
+
+ where(given_state_name: %w[test-state test.state test%2Ffoo])
+ with_them do
+ let(:state_name) { given_state_name }
+
+ it_behaves_like 'schedules the state for deletion'
+ end
+
+ context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
+ let(:state_name) { 'state-name-with-dot' }
+ let(:state_name_with_dot) { "#{state_name}.tfstate" }
+ let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name_with_dot}" }
+
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it_behaves_like 'schedules the state for deletion'
+ end
+
+ context 'with invalid state name' do
+ let(:state_name) { 'foo/bar' }
+
+ it 'returns a 404 error' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
it_behaves_like 'cannot access a state that is scheduled for deletion'
end
@@ -304,7 +432,7 @@ RSpec.describe API::Terraform::State, :snowplow do
end
end
- describe 'PUT /projects/:id/terraform/state/:name/lock' do
+ describe 'POST /projects/:id/terraform/state/:name/lock' do
let(:params) do
{
ID: '123-456',
@@ -322,10 +450,14 @@ RSpec.describe API::Terraform::State, :snowplow do
it_behaves_like 'endpoint with unique user tracking'
it_behaves_like 'cannot access a state that is scheduled for deletion'
- it 'locks the terraform state' do
- request
+ context 'with invalid state name' do
+ let(:state_name) { 'foo/bar' }
- expect(response).to have_gitlab_http_status(:ok)
+ it 'returns a 404 error' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
context 'state is already locked' do
@@ -349,6 +481,47 @@ RSpec.describe API::Terraform::State, :snowplow do
expect(response).to have_gitlab_http_status(:forbidden)
end
end
+
+ where(given_state_name: %w[test-state test%2Ffoo])
+ with_them do
+ let(:state_name) { given_state_name }
+
+ it 'locks the terraform state' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'with a dot in the state name' do
+ let(:state_name) { 'test.state' }
+
+ context 'with allow_dots_on_tf_state_names ff enabled' do
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: true)
+ end
+
+ let(:state_name) { 'test.state' }
+
+ it 'locks the terraform state' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'with allow_dots_on_tf_state_names ff disabled' do
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it 'returns 404' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
describe 'DELETE /projects/:id/terraform/state/:name/lock' do
@@ -365,8 +538,9 @@ RSpec.describe API::Terraform::State, :snowplow do
end
before do
- state.lock_xid = '123-456'
+ state.lock_xid = '123.456'
state.save!
+ stub_feature_flags(allow_dots_on_tf_state_names: true)
end
subject(:request) { delete api("#{state_path}/lock"), headers: auth_header, params: params }
@@ -379,28 +553,61 @@ RSpec.describe API::Terraform::State, :snowplow do
let(:lock_id) { 'irrelevant to this test, just needs to be present' }
end
- context 'with the correct lock id' do
- let(:lock_id) { '123-456' }
+ where(given_state_name: %w[test-state test.state test%2Ffoo])
+ with_them do
+ let(:state_name) { given_state_name }
- it 'removes the terraform state lock' do
- request
+ context 'with the correct lock id' do
+ let(:lock_id) { '123.456' }
- expect(response).to have_gitlab_http_status(:ok)
+ it 'removes the terraform state lock' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'with allow_dots_on_tf_state_names ff disabled' do
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ context 'with dots in the state name' do
+ let(:lock_id) { '123.456' }
+ let(:state_name) { 'test.state' }
+
+ it 'returns 404' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'with no lock id (force-unlock)' do
+ let(:params) { {} }
+
+ it 'removes the terraform state lock' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
end
end
- context 'with no lock id (force-unlock)' do
- let(:params) { {} }
+ context 'with invalid state name' do
+ let(:lock_id) { '123.456' }
+ let(:state_name) { 'foo/bar' }
- it 'removes the terraform state lock' do
+ it 'returns a 404 error' do
request
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with an incorrect lock id' do
- let(:lock_id) { '456-789' }
+ let(:lock_id) { '456.789' }
it 'returns an error' do
request
@@ -420,7 +627,7 @@ RSpec.describe API::Terraform::State, :snowplow do
end
context 'user does not have permission to unlock the state' do
- let(:lock_id) { '123-456' }
+ let(:lock_id) { '123.456' }
let(:current_user) { developer }
it 'returns an error' do
diff --git a/spec/requests/api/terraform/state_version_spec.rb b/spec/requests/api/terraform/state_version_spec.rb
index ade0aacf805..28abbb5749d 100644
--- a/spec/requests/api/terraform/state_version_spec.rb
+++ b/spec/requests/api/terraform/state_version_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Terraform::StateVersion do
+RSpec.describe API::Terraform::StateVersion, feature_category: :infrastructure_as_code do
include HttpBasicAuthHelpers
let_it_be(:project) { create(:project) }
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 7a626ee4d29..5a342f79926 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Todos do
+RSpec.describe API::Todos, feature_category: :source_code_management do
include DesignManagementTestHelpers
let_it_be(:group) { create(:group) }
@@ -15,6 +15,7 @@ RSpec.describe API::Todos do
let_it_be(:work_item) { create(:work_item, :task, project: project_1) }
let_it_be(:merge_request) { create(:merge_request, source_project: project_1) }
let_it_be(:alert) { create(:alert_management_alert, project: project_1) }
+ let_it_be(:group_request_todo) { create(:todo, author: author_1, user: john_doe, target: group, action: Todo::MEMBER_ACCESS_REQUESTED) }
let_it_be(:alert_todo) { create(:todo, project: project_1, author: john_doe, user: john_doe, target: alert) }
let_it_be(:merge_request_todo) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) }
let_it_be(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe, target: issue) }
@@ -71,7 +72,7 @@ RSpec.describe API::Todos do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.length).to eq(6)
+ expect(json_response.length).to eq(7)
expect(json_response[0]).to include(
'id' => pending_5.id,
@@ -127,6 +128,17 @@ RSpec.describe API::Todos do
'title' => alert.title
)
)
+
+ expect(json_response[6]).to include(
+ 'target_type' => 'Namespace',
+ 'action_name' => 'member_access_requested',
+ 'target' => hash_including(
+ 'id' => group.id,
+ 'name' => group.name,
+ 'full_path' => group.full_path
+ ),
+ 'target_url' => Gitlab::Routing.url_helpers.group_group_members_url(group, tab: 'access_requests')
+ )
end
context "when current user does not have access to one of the TODO's target" do
@@ -137,7 +149,7 @@ RSpec.describe API::Todos do
get api('/todos', john_doe)
- expect(json_response.count).to eq(6)
+ expect(json_response.count).to eq(7)
expect(json_response.map { |t| t['id'] }).not_to include(no_access_todo.id, pending_4.id)
end
end
@@ -231,7 +243,7 @@ RSpec.describe API::Todos do
create(:on_commit_todo, project: new_todo.project, author: author_1, user: john_doe, target: merge_request_3)
create(:todo, project: new_todo.project, author: author_2, user: john_doe, target: merge_request_3)
- expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control1).with_threshold(5)
+ expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control1).with_threshold(6)
control2 = ActiveRecord::QueryRecorder.new { get api('/todos', john_doe) }
create_issue_todo_for(john_doe)
diff --git a/spec/requests/api/topics_spec.rb b/spec/requests/api/topics_spec.rb
index 1ad6f876fab..14719292557 100644
--- a/spec/requests/api/topics_spec.rb
+++ b/spec/requests/api/topics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Topics do
+RSpec.describe API::Topics, feature_category: :projects do
include WorkhorseHelpers
let_it_be(:file) { fixture_file_upload('spec/fixtures/dk.png') }
diff --git a/spec/requests/api/unleash_spec.rb b/spec/requests/api/unleash_spec.rb
index 4d382f91023..5daf7cd7b75 100644
--- a/spec/requests/api/unleash_spec.rb
+++ b/spec/requests/api/unleash_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Unleash do
+RSpec.describe API::Unleash, feature_category: :feature_flags do
include FeatureFlagHelpers
let_it_be(:project, refind: true) { create(:project) }
@@ -88,85 +88,6 @@ RSpec.describe API::Unleash do
end
end
- shared_examples_for 'support multiple environments' do
- let!(:client) { create(:operations_feature_flags_client, project: project) }
- let!(:base_headers) { { "UNLEASH-INSTANCEID" => client.token } }
- let!(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "test" }) }
-
- let!(:feature_flag_1) do
- create(:operations_feature_flag, name: "feature_flag_1", project: project, active: true)
- end
-
- let!(:feature_flag_2) do
- create(:operations_feature_flag, name: "feature_flag_2", project: project, active: false)
- end
-
- before do
- create_scope(feature_flag_1, 'production', false)
- create_scope(feature_flag_2, 'review/*', true)
- end
-
- it 'does not have N+1 problem' do
- control_count = ActiveRecord::QueryRecorder.new { get api(features_url), headers: headers }.count
-
- create(:operations_feature_flag, name: "feature_flag_3", project: project, active: true)
-
- expect { get api(features_url), headers: headers }.not_to exceed_query_limit(control_count)
- end
-
- context 'when app name is staging' do
- let(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "staging" }) }
-
- it 'returns correct active values' do
- subject
-
- feature_flag_1 = json_response['features'].find { |f| f['name'] == 'feature_flag_1' }
- feature_flag_2 = json_response['features'].find { |f| f['name'] == 'feature_flag_2' }
-
- expect(feature_flag_1['enabled']).to eq(true)
- expect(feature_flag_2['enabled']).to eq(false)
- end
- end
-
- context 'when app name is production' do
- let(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "production" }) }
-
- it 'returns correct active values' do
- subject
-
- feature_flag_1 = json_response['features'].find { |f| f['name'] == 'feature_flag_1' }
- feature_flag_2 = json_response['features'].find { |f| f['name'] == 'feature_flag_2' }
-
- expect(feature_flag_1['enabled']).to eq(false)
- expect(feature_flag_2['enabled']).to eq(false)
- end
- end
-
- context 'when app name is review/patch-1' do
- let(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "review/patch-1" }) }
-
- it 'returns correct active values' do
- subject
-
- feature_flag_1 = json_response['features'].find { |f| f['name'] == 'feature_flag_1' }
- feature_flag_2 = json_response['features'].find { |f| f['name'] == 'feature_flag_2' }
-
- expect(feature_flag_1['enabled']).to eq(true)
- expect(feature_flag_2['enabled']).to eq(false)
- end
- end
-
- context 'when app name is empty' do
- let(:headers) { base_headers }
-
- it 'returns empty list' do
- subject
-
- expect(json_response['features'].count).to eq(0)
- end
- end
- end
-
%w(/feature_flags/unleash/:project_id/features /feature_flags/unleash/:project_id/client/features).each do |features_endpoint|
describe "GET #{features_endpoint}", :use_clean_rails_redis_caching do
let(:features_url) { features_endpoint.sub(':project_id', project_id.to_s) }
diff --git a/spec/requests/api/usage_data_non_sql_metrics_spec.rb b/spec/requests/api/usage_data_non_sql_metrics_spec.rb
index 0b73d0f96a4..0a6f248af2c 100644
--- a/spec/requests/api/usage_data_non_sql_metrics_spec.rb
+++ b/spec/requests/api/usage_data_non_sql_metrics_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::UsageDataNonSqlMetrics do
+RSpec.describe API::UsageDataNonSqlMetrics, feature_category: :service_ping do
include UsageDataHelpers
let_it_be(:admin) { create(:user, admin: true) }
diff --git a/spec/requests/api/usage_data_queries_spec.rb b/spec/requests/api/usage_data_queries_spec.rb
index 6ce03954246..e556064025c 100644
--- a/spec/requests/api/usage_data_queries_spec.rb
+++ b/spec/requests/api/usage_data_queries_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'rake_helper'
-RSpec.describe API::UsageDataQueries do
+RSpec.describe API::UsageDataQueries, feature_category: :service_ping do
include UsageDataHelpers
let_it_be(:admin) { create(:user, admin: true) }
@@ -80,7 +80,7 @@ RSpec.describe API::UsageDataQueries do
end
it 'matches the generated query' do
- Timecop.freeze(2021, 1, 1) do
+ travel_to(Time.utc(2021, 1, 1)) do
get api(endpoint, admin)
end
diff --git a/spec/requests/api/usage_data_spec.rb b/spec/requests/api/usage_data_spec.rb
index d532fb6c168..935ddbf4764 100644
--- a/spec/requests/api/usage_data_spec.rb
+++ b/spec/requests/api/usage_data_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::UsageData do
+RSpec.describe API::UsageData, feature_category: :service_ping do
let_it_be(:user) { create(:user) }
describe 'POST /usage_data/increment_counter' do
diff --git a/spec/requests/api/user_counts_spec.rb b/spec/requests/api/user_counts_spec.rb
index 369ae49de08..27e5311e2eb 100644
--- a/spec/requests/api/user_counts_spec.rb
+++ b/spec/requests/api/user_counts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::UserCounts do
+RSpec.describe API::UserCounts, feature_category: :service_ping do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let_it_be(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
diff --git a/spec/requests/api/users_preferences_spec.rb b/spec/requests/api/users_preferences_spec.rb
index 97e37263ee6..53f366371e5 100644
--- a/spec/requests/api/users_preferences_spec.rb
+++ b/spec/requests/api/users_preferences_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Users do
+RSpec.describe API::Users, feature_category: :users do
let_it_be(:user) { create(:user) }
describe 'PUT /user/preferences/' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 6688a998a1a..bfb71d95f5e 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Users do
+RSpec.describe API::Users, feature_category: :users do
include WorkhorseHelpers
let_it_be(:admin) { create(:admin) }
@@ -1988,11 +1988,19 @@ RSpec.describe API::Users do
expect(json_response['error']).to eq('title is missing')
end
- it "creates ssh key" do
- key_attrs = attributes_for :key
+ it "creates ssh key", :aggregate_failures do
+ key_attrs = attributes_for(:key, usage_type: :signing)
+
expect do
post api("/users/#{user.id}/keys", admin), params: key_attrs
end.to change { user.keys.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:created)
+
+ key = user.keys.last
+ expect(key.title).to eq(key_attrs[:title])
+ expect(key.key).to eq(key_attrs[:key])
+ expect(key.usage_type).to eq(key_attrs[:usage_type].to_s)
end
it 'creates SSH key with `expires_at` attribute' do
@@ -2848,12 +2856,19 @@ RSpec.describe API::Users do
end
describe "POST /user/keys" do
- it "creates ssh key" do
- key_attrs = attributes_for :key
+ it "creates ssh key", :aggregate_failures do
+ key_attrs = attributes_for(:key, usage_type: :signing)
+
expect do
post api("/user/keys", user), params: key_attrs
end.to change { user.keys.count }.by(1)
+
expect(response).to have_gitlab_http_status(:created)
+
+ key = user.keys.last
+ expect(key.title).to eq(key_attrs[:title])
+ expect(key.key).to eq(key_attrs[:key])
+ expect(key.usage_type).to eq(key_attrs[:usage_type].to_s)
end
it 'creates SSH key with `expires_at` attribute' do
diff --git a/spec/requests/api/v3/github_spec.rb b/spec/requests/api/v3/github_spec.rb
index 5bfea15f0ca..0b8fac5c55c 100644
--- a/spec/requests/api/v3/github_spec.rb
+++ b/spec/requests/api/v3/github_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::V3::Github do
+RSpec.describe API::V3::Github, feature_category: :integrations do
let_it_be(:user) { create(:user) }
let_it_be(:unauthorized_user) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
diff --git a/spec/requests/api/wikis_spec.rb b/spec/requests/api/wikis_spec.rb
index f4096eef8d0..00e38a5bb7e 100644
--- a/spec/requests/api/wikis_spec.rb
+++ b/spec/requests/api/wikis_spec.rb
@@ -12,7 +12,7 @@ require 'spec_helper'
# - maintainer
# because they are 3 edge cases of using wiki pages.
-RSpec.describe API::Wikis do
+RSpec.describe API::Wikis, feature_category: :wiki do
include WorkhorseHelpers
include AfterNextHelpers