Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2017-08-03 02:58:28 +0300
committerStan Hu <stanhu@gmail.com>2017-08-03 02:58:28 +0300
commit408df2edcbd5f3f93ef5541bac9de2b71ba4f0ea (patch)
tree708ae61f9683b48f436f7577d1fad98f30e100fc /spec
parent3f81586ef0ab20533b8da1213bd9f60e1786dbaa (diff)
parentfaa2a123911eaf84bb57163ea7af759d4632601b (diff)
Merge branch 'master' into sh-headless-chrome-support
Diffstat (limited to 'spec')
-rw-r--r--spec/config/mail_room_spec.rb22
-rw-r--r--spec/controllers/abuse_reports_controller_spec.rb25
-rw-r--r--spec/controllers/admin/applications_controller_spec.rb11
-rw-r--r--spec/controllers/admin/dashboard_controller_spec.rb21
-rw-r--r--spec/controllers/application_controller_spec.rb39
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb15
-rw-r--r--spec/controllers/dashboard/labels_controller_spec.rb25
-rw-r--r--spec/controllers/dashboard/todos_controller_spec.rb30
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb123
-rw-r--r--spec/controllers/groups/settings/ci_cd_controller_spec.rb20
-rw-r--r--spec/controllers/groups/variables_controller_spec.rb56
-rw-r--r--spec/controllers/health_check_controller_spec.rb75
-rw-r--r--spec/controllers/health_controller_spec.rb103
-rw-r--r--spec/controllers/metrics_controller_spec.rb70
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb2
-rw-r--r--spec/controllers/passwords_controller_spec.rb29
-rw-r--r--spec/controllers/profiles/accounts_controller_spec.rb2
-rw-r--r--spec/controllers/profiles/preferences_controller_spec.rb5
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb11
-rw-r--r--spec/controllers/projects/badges_controller_spec.rb28
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb11
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb8
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb11
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb4
-rw-r--r--spec/controllers/projects/deployments_controller_spec.rb64
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb52
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb6
-rw-r--r--spec/controllers/projects/hooks_controller_spec.rb21
-rw-r--r--spec/controllers/projects/imports_controller_spec.rb10
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb103
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb4
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb4
-rw-r--r--spec/controllers/projects/mattermosts_controller_spec.rb4
-rw-r--r--spec/controllers/projects/merge_requests/conflicts_controller_spec.rb307
-rw-r--r--spec/controllers/projects/merge_requests/creations_controller_spec.rb120
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb160
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb611
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb34
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb62
-rw-r--r--spec/controllers/projects/pages_domains_controller_spec.rb4
-rw-r--r--spec/controllers/projects/pipeline_schedules_controller_spec.rb327
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb7
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb19
-rw-r--r--spec/controllers/projects/prometheus_controller_spec.rb59
-rw-r--r--spec/controllers/projects/registry/tags_controller_spec.rb48
-rw-r--r--spec/controllers/projects/services_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/members_controller_spec.rb14
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb6
-rw-r--r--spec/controllers/projects/variables_controller_spec.rb9
-rw-r--r--spec/controllers/projects_controller_spec.rb43
-rw-r--r--spec/controllers/sent_notifications_controller_spec.rb12
-rw-r--r--spec/controllers/sessions_controller_spec.rb10
-rw-r--r--spec/controllers/snippets_controller_spec.rb10
-rw-r--r--spec/controllers/uploads_controller_spec.rb4
-rw-r--r--spec/controllers/users_controller_spec.rb4
-rw-r--r--spec/db/production/settings_spec.rb2
-rw-r--r--spec/factories/ci/builds.rb9
-rw-r--r--spec/factories/ci/group_variables.rb12
-rw-r--r--spec/factories/ci/pipeline_schedule_variables.rb8
-rw-r--r--spec/factories/ci/pipeline_variable_variables.rb8
-rw-r--r--spec/factories/ci/runner_projects.rb4
-rw-r--r--spec/factories/ci/triggers.rb7
-rw-r--r--spec/factories/commits.rb9
-rw-r--r--spec/factories/gpg_keys.rb8
-rw-r--r--spec/factories/gpg_signature.rb11
-rw-r--r--spec/factories/issues.rb6
-rw-r--r--spec/factories/merge_requests.rb6
-rw-r--r--spec/factories/milestones.rb22
-rw-r--r--spec/factories/personal_snippets.rb4
-rw-r--r--spec/factories/project_hooks.rb1
-rw-r--r--spec/factories/project_snippets.rb5
-rw-r--r--spec/factories/projects.rb6
-rw-r--r--spec/factories/protected_branches.rb50
-rw-r--r--spec/factories/protected_tags.rb36
-rw-r--r--spec/factories/services.rb8
-rw-r--r--spec/factories/snippets.rb7
-rw-r--r--spec/factories/uploads.rb2
-rw-r--r--spec/features/abuse_report_spec.rb6
-rw-r--r--spec/features/admin/admin_abuse_reports_spec.rb4
-rw-r--r--spec/features/admin/admin_active_tab_spec.rb2
-rw-r--r--spec/features/admin/admin_appearance_spec.rb14
-rw-r--r--spec/features/admin/admin_broadcast_messages_spec.rb4
-rw-r--r--spec/features/admin/admin_browse_spam_logs_spec.rb2
-rw-r--r--spec/features/admin/admin_browses_logs_spec.rb2
-rw-r--r--spec/features/admin/admin_builds_spec.rb2
-rw-r--r--spec/features/admin/admin_cohorts_spec.rb4
-rw-r--r--spec/features/admin/admin_conversational_development_index_spec.rb2
-rw-r--r--spec/features/admin/admin_deploy_keys_spec.rb4
-rw-r--r--spec/features/admin/admin_disables_git_access_protocol_spec.rb6
-rw-r--r--spec/features/admin/admin_disables_two_factor_spec.rb6
-rw-r--r--spec/features/admin/admin_groups_spec.rb5
-rw-r--r--spec/features/admin/admin_health_check_spec.rb4
-rw-r--r--spec/features/admin/admin_hook_logs_spec.rb6
-rw-r--r--spec/features/admin/admin_hooks_spec.rb12
-rw-r--r--spec/features/admin/admin_labels_spec.rb2
-rw-r--r--spec/features/admin/admin_manage_applications_spec.rb9
-rw-r--r--spec/features/admin/admin_projects_spec.rb31
-rw-r--r--spec/features/admin/admin_requests_profiles_spec.rb4
-rw-r--r--spec/features/admin/admin_runners_spec.rb68
-rw-r--r--spec/features/admin/admin_settings_spec.rb17
-rw-r--r--spec/features/admin/admin_system_info_spec.rb2
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb20
-rw-r--r--spec/features/admin/admin_users_spec.rb10
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb6
-rw-r--r--spec/features/atom/dashboard_issues_spec.rb6
-rw-r--r--spec/features/atom/dashboard_spec.rb4
-rw-r--r--spec/features/atom/issues_spec.rb14
-rw-r--r--spec/features/atom/users_spec.rb4
-rw-r--r--spec/features/auto_deploy_spec.rb6
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb8
-rw-r--r--spec/features/boards/boards_spec.rb25
-rw-r--r--spec/features/boards/issue_ordering_spec.rb10
-rw-r--r--spec/features/boards/keyboard_shortcut_spec.rb6
-rw-r--r--spec/features/boards/modal_filter_spec.rb6
-rw-r--r--spec/features/boards/new_issue_spec.rb8
-rw-r--r--spec/features/boards/sidebar_spec.rb22
-rw-r--r--spec/features/boards/sub_group_project_spec.rb6
-rw-r--r--spec/features/calendar_spec.rb4
-rw-r--r--spec/features/ci_lint_spec.rb2
-rw-r--r--spec/features/commits_spec.rb111
-rw-r--r--spec/features/container_registry_spec.rb5
-rw-r--r--spec/features/copy_as_gfm_spec.rb20
-rw-r--r--spec/features/cycle_analytics_spec.rb18
-rw-r--r--spec/features/dashboard/active_tab_spec.rb4
-rw-r--r--spec/features/dashboard/activity_spec.rb161
-rw-r--r--spec/features/dashboard/archived_projects_spec.rb6
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb8
-rw-r--r--spec/features/dashboard/group_spec.rb4
-rw-r--r--spec/features/dashboard/groups_list_spec.rb12
-rw-r--r--spec/features/dashboard/help_spec.rb4
-rw-r--r--spec/features/dashboard/issuables_counter_spec.rb4
-rw-r--r--spec/features/dashboard/issues_filter_spec.rb (renamed from spec/features/dashboard_issues_spec.rb)60
-rw-r--r--spec/features/dashboard/issues_spec.rb22
-rw-r--r--spec/features/dashboard/label_filter_spec.rb8
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb112
-rw-r--r--spec/features/dashboard/milestone_filter_spec.rb26
-rw-r--r--spec/features/dashboard/milestone_tabs_spec.rb4
-rw-r--r--spec/features/dashboard/milestones_spec.rb (renamed from spec/features/dashboard_milestones_spec.rb)4
-rw-r--r--spec/features/dashboard/project_member_activity_index_spec.rb4
-rw-r--r--spec/features/dashboard/projects_spec.rb91
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb4
-rw-r--r--spec/features/dashboard/snippets_spec.rb6
-rw-r--r--spec/features/dashboard/todos/target_state_spec.rb (renamed from spec/features/todos/target_state_spec.rb)10
-rw-r--r--spec/features/dashboard/todos/todos_filtering_spec.rb (renamed from spec/features/todos/todos_filtering_spec.rb)14
-rw-r--r--spec/features/dashboard/todos/todos_sorting_spec.rb (renamed from spec/features/todos/todos_sorting_spec.rb)58
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb338
-rw-r--r--spec/features/dashboard/user_filters_projects_spec.rb8
-rw-r--r--spec/features/discussion_comments/commit_spec.rb6
-rw-r--r--spec/features/discussion_comments/issue_spec.rb6
-rw-r--r--spec/features/discussion_comments/merge_request_spec.rb6
-rw-r--r--spec/features/discussion_comments/snippets_spec.rb6
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb12
-rw-r--r--spec/features/explore/groups_list_spec.rb4
-rw-r--r--spec/features/explore/new_menu_spec.rb43
-rw-r--r--spec/features/gitlab_flavored_markdown_spec.rb28
-rw-r--r--spec/features/global_search_spec.rb4
-rw-r--r--spec/features/group_variables_spec.rb78
-rw-r--r--spec/features/groups/activity_spec.rb6
-rw-r--r--spec/features/groups/empty_states_spec.rb2
-rw-r--r--spec/features/groups/group_name_toggle_spec.rb4
-rw-r--r--spec/features/groups/group_settings_spec.rb18
-rw-r--r--spec/features/groups/issues_spec.rb2
-rw-r--r--spec/features/groups/labels/edit_spec.rb4
-rw-r--r--spec/features/groups/labels/subscription_spec.rb51
-rw-r--r--spec/features/groups/members/last_owner_cannot_leave_group_spec.rb16
-rw-r--r--spec/features/groups/members/leave_group_spec.rb62
-rw-r--r--spec/features/groups/members/list_members_spec.rb42
-rw-r--r--spec/features/groups/members/manage_access_requests_spec.rb (renamed from spec/features/groups/members/owner_manages_access_requests_spec.rb)8
-rw-r--r--spec/features/groups/members/manage_members.rb (renamed from spec/features/groups/members/list_spec.rb)54
-rw-r--r--spec/features/groups/members/member_cannot_request_access_to_his_project_spec.rb16
-rw-r--r--spec/features/groups/members/member_leaves_group_spec.rb21
-rw-r--r--spec/features/groups/members/request_access_spec.rb (renamed from spec/features/groups/members/user_requests_access_spec.rb)13
-rw-r--r--spec/features/groups/members/sort_members_spec.rb (renamed from spec/features/groups/members/sorting_spec.rb)8
-rw-r--r--spec/features/groups/merge_requests_spec.rb4
-rw-r--r--spec/features/groups/milestone_spec.rb32
-rw-r--r--spec/features/groups/show_spec.rb9
-rw-r--r--spec/features/groups_spec.rb24
-rw-r--r--spec/features/help_pages_spec.rb6
-rw-r--r--spec/features/issuables/close_reopen_report_toggle_spec.rb116
-rw-r--r--spec/features/issuables/default_sort_order_spec.rb2
-rw-r--r--spec/features/issuables/issuable_list_spec.rb8
-rw-r--r--spec/features/issuables/markdown_references_spec.rb193
-rw-r--r--spec/features/issuables/user_sees_sidebar_spec.rb30
-rw-r--r--spec/features/issues/award_emoji_spec.rb12
-rw-r--r--spec/features/issues/award_spec.rb14
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb12
-rw-r--r--spec/features/issues/create_branch_merge_request_spec.rb28
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb26
-rw-r--r--spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb21
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_hint_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_label_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb12
-rw-r--r--spec/features/issues/filtered_search/recent_searches_spec.rb20
-rw-r--r--spec/features/issues/filtered_search/search_bar_spec.rb6
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb8
-rw-r--r--spec/features/issues/form_spec.rb23
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb20
-rw-r--r--spec/features/issues/group_label_sidebar_spec.rb10
-rw-r--r--spec/features/issues/issue_detail_spec.rb43
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb22
-rw-r--r--spec/features/issues/markdown_toolbar_spec.rb10
-rw-r--r--spec/features/issues/move_spec.rb23
-rw-r--r--spec/features/issues/note_polling_spec.rb16
-rw-r--r--spec/features/issues/notes_on_issues_spec.rb18
-rw-r--r--spec/features/issues/spam_issues_spec.rb10
-rw-r--r--spec/features/issues/todo_spec.rb16
-rw-r--r--spec/features/issues/update_issues_spec.rb26
-rw-r--r--spec/features/issues/user_uses_slash_commands_spec.rb95
-rw-r--r--spec/features/issues_spec.rb80
-rw-r--r--spec/features/login_spec.rb29
-rw-r--r--spec/features/markdown_spec.rb4
-rw-r--r--spec/features/merge_requests/assign_issues_spec.rb8
-rw-r--r--spec/features/merge_requests/award_spec.rb14
-rw-r--r--spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb8
-rw-r--r--spec/features/merge_requests/cherry_pick_spec.rb8
-rw-r--r--spec/features/merge_requests/closes_issues_spec.rb8
-rw-r--r--spec/features/merge_requests/conflicts_spec.rb19
-rw-r--r--spec/features/merge_requests/create_new_mr_spec.rb34
-rw-r--r--spec/features/merge_requests/created_from_fork_spec.rb36
-rw-r--r--spec/features/merge_requests/deleted_source_branch_spec.rb10
-rw-r--r--spec/features/merge_requests/diff_notes_avatars_spec.rb16
-rw-r--r--spec/features/merge_requests/diff_notes_resolve_spec.rb12
-rw-r--r--spec/features/merge_requests/diffs_spec.rb20
-rw-r--r--spec/features/merge_requests/discussion_spec.rb12
-rw-r--r--spec/features/merge_requests/edit_mr_spec.rb10
-rw-r--r--spec/features/merge_requests/filter_by_labels_spec.rb8
-rw-r--r--spec/features/merge_requests/filter_by_milestone_spec.rb6
-rw-r--r--spec/features/merge_requests/filter_merge_requests_spec.rb32
-rw-r--r--spec/features/merge_requests/form_spec.rb32
-rw-r--r--spec/features/merge_requests/merge_commit_message_toggle_spec.rb8
-rw-r--r--spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb8
-rw-r--r--spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb10
-rw-r--r--spec/features/merge_requests/mini_pipeline_graph_spec.rb10
-rw-r--r--spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb6
-rw-r--r--spec/features/merge_requests/pipelines_spec.rb8
-rw-r--r--spec/features/merge_requests/reset_filters_spec.rb4
-rw-r--r--spec/features/merge_requests/target_branch_spec.rb9
-rw-r--r--spec/features/merge_requests/toggle_whitespace_changes_spec.rb6
-rw-r--r--spec/features/merge_requests/toggler_behavior_spec.rb8
-rw-r--r--spec/features/merge_requests/update_merge_requests_spec.rb18
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb8
-rw-r--r--spec/features/merge_requests/user_posts_diff_notes_spec.rb16
-rw-r--r--spec/features/merge_requests/user_posts_notes_spec.rb6
-rw-r--r--spec/features/merge_requests/user_sees_system_notes_spec.rb10
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb44
-rw-r--r--spec/features/merge_requests/versions_spec.rb9
-rw-r--r--spec/features/merge_requests/widget_deployments_spec.rb6
-rw-r--r--spec/features/merge_requests/widget_spec.rb38
-rw-r--r--spec/features/merge_requests/wip_message_spec.rb18
-rw-r--r--spec/features/milestone_spec.rb33
-rw-r--r--spec/features/milestones/show_spec.rb6
-rw-r--r--spec/features/oauth_login_spec.rb114
-rw-r--r--spec/features/participants_autocomplete_spec.rb11
-rw-r--r--spec/features/password_reset_spec.rb2
-rw-r--r--spec/features/profile_spec.rb4
-rw-r--r--spec/features/profiles/account_spec.rb10
-rw-r--r--spec/features/profiles/chat_names_spec.rb4
-rw-r--r--spec/features/profiles/gpg_keys_spec.rb58
-rw-r--r--spec/features/profiles/keys_spec.rb4
-rw-r--r--spec/features/profiles/oauth_applications_spec.rb4
-rw-r--r--spec/features/profiles/password_spec.rb82
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb16
-rw-r--r--spec/features/profiles/preferences_spec.rb4
-rw-r--r--spec/features/profiles/user_changes_notified_of_own_activity_spec.rb4
-rw-r--r--spec/features/profiles/user_visits_notifications_tab_spec.rb21
-rw-r--r--spec/features/projects/activity/rss_spec.rb6
-rw-r--r--spec/features/projects/artifacts/browse_spec.rb8
-rw-r--r--spec/features/projects/artifacts/download_spec.rb14
-rw-r--r--spec/features/projects/artifacts/file_spec.rb8
-rw-r--r--spec/features/projects/artifacts/raw_spec.rb8
-rw-r--r--spec/features/projects/badges/coverage_spec.rb11
-rw-r--r--spec/features/projects/badges/list_spec.rb18
-rw-r--r--spec/features/projects/badges/pipeline_badge_spec.rb70
-rw-r--r--spec/features/projects/blobs/blob_line_permalink_updater_spec.rb22
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb6
-rw-r--r--spec/features/projects/blobs/edit_spec.rb32
-rw-r--r--spec/features/projects/blobs/shortcuts_blob_spec.rb8
-rw-r--r--spec/features/projects/branches/download_buttons_spec.rb12
-rw-r--r--spec/features/projects/branches/new_branch_ref_dropdown_spec.rb8
-rw-r--r--spec/features/projects/branches_spec.rb73
-rw-r--r--spec/features/projects/commit/builds_spec.rb6
-rw-r--r--spec/features/projects/commit/cherry_pick_spec.rb6
-rw-r--r--spec/features/projects/commit/mini_pipeline_graph_spec.rb10
-rw-r--r--spec/features/projects/commit/rss_spec.rb6
-rw-r--r--spec/features/projects/compare_spec.rb6
-rw-r--r--spec/features/projects/deploy_keys_spec.rb6
-rw-r--r--spec/features/projects/developer_views_empty_project_instructions_spec.rb6
-rw-r--r--spec/features/projects/diffs/diff_show_spec.rb8
-rw-r--r--spec/features/projects/edit_spec.rb12
-rw-r--r--spec/features/projects/environments/environment_metrics_spec.rb10
-rw-r--r--spec/features/projects/environments/environment_spec.rb20
-rw-r--r--spec/features/projects/environments/environments_spec.rb20
-rw-r--r--spec/features/projects/features_visibility_spec.rb69
-rw-r--r--spec/features/projects/files/browse_files_spec.rb10
-rw-r--r--spec/features/projects/files/creating_a_file_spec.rb13
-rw-r--r--spec/features/projects/files/dockerfile_dropdown_spec.rb8
-rw-r--r--spec/features/projects/files/download_buttons_spec.rb13
-rw-r--r--spec/features/projects/files/edit_file_soft_wrap_spec.rb8
-rw-r--r--spec/features/projects/files/editing_a_file_spec.rb8
-rw-r--r--spec/features/projects/files/files_sort_submodules_with_folders_spec.rb6
-rw-r--r--spec/features/projects/files/find_file_keyboard_spec.rb8
-rw-r--r--spec/features/projects/files/find_files_spec.rb17
-rw-r--r--spec/features/projects/files/gitignore_dropdown_spec.rb8
-rw-r--r--spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb8
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb16
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb10
-rw-r--r--spec/features/projects/files/template_type_dropdown_spec.rb14
-rw-r--r--spec/features/projects/files/undo_template_spec.rb8
-rw-r--r--spec/features/projects/gfm_autocomplete_load_spec.rb10
-rw-r--r--spec/features/projects/group_links_spec.rb14
-rw-r--r--spec/features/projects/guest_navigation_menu_spec.rb16
-rw-r--r--spec/features/projects/import_export/export_file_spec.rb8
-rw-r--r--spec/features/projects/import_export/import_file_spec.rb9
-rw-r--r--spec/features/projects/import_export/namespace_export_file_spec.rb8
-rw-r--r--spec/features/projects/issuable_counts_caching_spec.rb132
-rw-r--r--spec/features/projects/issuable_templates_spec.rb23
-rw-r--r--spec/features/projects/issues/list_spec.rb4
-rw-r--r--spec/features/projects/issues/rss_spec.rb7
-rw-r--r--spec/features/projects/jobs_spec.rb81
-rw-r--r--spec/features/projects/labels/issues_sorted_by_priority_spec.rb12
-rw-r--r--spec/features/projects/labels/subscription_spec.rb8
-rw-r--r--spec/features/projects/labels/update_prioritization_spec.rb28
-rw-r--r--spec/features/projects/main/download_buttons_spec.rb12
-rw-r--r--spec/features/projects/main/rss_spec.rb6
-rw-r--r--spec/features/projects/members/anonymous_user_sees_members_spec.rb6
-rw-r--r--spec/features/projects/members/group_links_spec.rb8
-rw-r--r--spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb8
-rw-r--r--spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb8
-rw-r--r--spec/features/projects/members/group_members_spec.rb12
-rw-r--r--spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb8
-rw-r--r--spec/features/projects/members/list_spec.rb8
-rw-r--r--spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb10
-rw-r--r--spec/features/projects/members/master_manages_access_requests_spec.rb10
-rw-r--r--spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb8
-rw-r--r--spec/features/projects/members/member_leaves_project_spec.rb8
-rw-r--r--spec/features/projects/members/owner_cannot_leave_project_spec.rb8
-rw-r--r--spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb8
-rw-r--r--spec/features/projects/members/sorting_spec.rb10
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb19
-rw-r--r--spec/features/projects/merge_request_button_spec.rb48
-rw-r--r--spec/features/projects/merge_requests/list_spec.rb14
-rw-r--r--spec/features/projects/milestones/milestone_spec.rb10
-rw-r--r--spec/features/projects/milestones/milestones_sorting_spec.rb6
-rw-r--r--spec/features/projects/milestones/new_spec.rb4
-rw-r--r--spec/features/projects/new_project_spec.rb89
-rw-r--r--spec/features/projects/no_password_spec.rb69
-rw-r--r--spec/features/projects/pages_spec.rb10
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb277
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb18
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb32
-rw-r--r--spec/features/projects/project_settings_spec.rb26
-rw-r--r--spec/features/projects/ref_switcher_spec.rb12
-rw-r--r--spec/features/projects/services/jira_service_spec.rb31
-rw-r--r--spec/features/projects/services/mattermost_slash_command_spec.rb12
-rw-r--r--spec/features/projects/services/slack_service_spec.rb8
-rw-r--r--spec/features/projects/services/slack_slash_command_spec.rb14
-rw-r--r--spec/features/projects/settings/integration_settings_spec.rb39
-rw-r--r--spec/features/projects/settings/merge_requests_settings_spec.rb6
-rw-r--r--spec/features/projects/settings/pipelines_settings_spec.rb8
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb16
-rw-r--r--spec/features/projects/settings/visibility_settings_spec.rb12
-rw-r--r--spec/features/projects/shortcuts_spec.rb8
-rw-r--r--spec/features/projects/show_project_spec.rb20
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb10
-rw-r--r--spec/features/projects/snippets/show_spec.rb10
-rw-r--r--spec/features/projects/snippets_spec.rb10
-rw-r--r--spec/features/projects/sub_group_issuables_spec.rb8
-rw-r--r--spec/features/projects/tags/download_buttons_spec.rb10
-rw-r--r--spec/features/projects/tree/rss_spec.rb6
-rw-r--r--spec/features/projects/user_browses_files_spec.rb188
-rw-r--r--spec/features/projects/user_create_dir_spec.rb57
-rw-r--r--spec/features/projects/user_creates_directory_spec.rb87
-rw-r--r--spec/features/projects/user_creates_files_spec.rb153
-rw-r--r--spec/features/projects/user_creates_project_spec.rb2
-rw-r--r--spec/features/projects/user_deletes_files_spec.rb68
-rw-r--r--spec/features/projects/user_edits_files_spec.rb122
-rw-r--r--spec/features/projects/user_replaces_files_spec.rb87
-rw-r--r--spec/features/projects/user_uploads_files_spec.rb82
-rw-r--r--spec/features/projects/view_on_env_spec.rb24
-rw-r--r--spec/features/projects/wiki/markdown_preview_spec.rb8
-rw-r--r--spec/features/projects/wiki/shortcuts_spec.rb6
-rw-r--r--spec/features/projects/wiki/user_creates_wiki_page_spec.rb31
-rw-r--r--spec/features/projects/wiki/user_git_access_wiki_page_spec.rb8
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb22
-rw-r--r--spec/features/projects/wiki/user_views_project_wiki_page_spec.rb15
-rw-r--r--spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb12
-rw-r--r--spec/features/projects_spec.rb26
-rw-r--r--spec/features/protected_branches_spec.rb18
-rw-r--r--spec/features/protected_tags_spec.rb18
-rw-r--r--spec/features/raven_js_spec.rb2
-rw-r--r--spec/features/reportable_note/commit_spec.rb8
-rw-r--r--spec/features/reportable_note/issue_spec.rb6
-rw-r--r--spec/features/reportable_note/merge_request_spec.rb6
-rw-r--r--spec/features/reportable_note/snippets_spec.rb6
-rw-r--r--spec/features/runners_spec.rb6
-rw-r--r--spec/features/search_spec.rb22
-rw-r--r--spec/features/security/admin_access_spec.rb2
-rw-r--r--spec/features/security/dashboard_access_spec.rb2
-rw-r--r--spec/features/security/group/internal_access_spec.rb5
-rw-r--r--spec/features/security/group/private_access_spec.rb5
-rw-r--r--spec/features/security/group/public_access_spec.rb5
-rw-r--r--spec/features/security/profile_access_spec.rb2
-rw-r--r--spec/features/security/project/internal_access_spec.rb66
-rw-r--r--spec/features/security/project/private_access_spec.rb66
-rw-r--r--spec/features/security/project/public_access_spec.rb66
-rw-r--r--spec/features/security/project/snippet/internal_access_spec.rb14
-rw-r--r--spec/features/security/project/snippet/private_access_spec.rb10
-rw-r--r--spec/features/security/project/snippet/public_access_spec.rb18
-rw-r--r--spec/features/signup_spec.rb2
-rw-r--r--spec/features/snippets/explore_spec.rb6
-rw-r--r--spec/features/snippets/internal_snippet_spec.rb4
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb5
-rw-r--r--spec/features/snippets/public_snippets_spec.rb2
-rw-r--r--spec/features/snippets/search_snippets_spec.rb6
-rw-r--r--spec/features/snippets/show_spec.rb2
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb (renamed from spec/features/snippets/create_snippet_spec.rb)12
-rw-r--r--spec/features/snippets/user_deletes_snippet_spec.rb19
-rw-r--r--spec/features/snippets/user_edits_snippet_spec.rb (renamed from spec/features/snippets/edit_snippet_spec.rb)28
-rw-r--r--spec/features/snippets/user_snippets_spec.rb4
-rw-r--r--spec/features/snippets_spec.rb2
-rw-r--r--spec/features/tags/master_creates_tag_spec.rb12
-rw-r--r--spec/features/tags/master_deletes_tag_spec.rb10
-rw-r--r--spec/features/tags/master_updates_tag_spec.rb10
-rw-r--r--spec/features/tags/master_views_tags_spec.rb24
-rw-r--r--spec/features/task_lists_spec.rb20
-rw-r--r--spec/features/triggers_spec.rb22
-rw-r--r--spec/features/unsubscribe_links_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_group_spec.rb6
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_profile_spec.rb6
-rw-r--r--spec/features/uploads/user_uploads_file_to_note_spec.rb6
-rw-r--r--spec/features/user_callout_spec.rb2
-rw-r--r--spec/features/user_can_display_performance_bar_spec.rb29
-rw-r--r--spec/features/users/projects_spec.rb4
-rw-r--r--spec/features/users/rss_spec.rb3
-rw-r--r--spec/features/users/snippets_spec.rb4
-rw-r--r--spec/features/users_spec.rb2
-rw-r--r--spec/features/variables_spec.rb20
-rw-r--r--spec/finders/access_requests_finder_spec.rb2
-rw-r--r--spec/finders/admin/projects_finder_spec.rb136
-rw-r--r--spec/finders/issues_finder_spec.rb140
-rw-r--r--spec/finders/labels_finder_spec.rb6
-rw-r--r--spec/finders/merge_requests_finder_spec.rb19
-rw-r--r--spec/finders/milestones_finder_spec.rb90
-rw-r--r--spec/finders/users_finder_spec.rb11
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request.json1
-rw-r--r--spec/fixtures/api/schemas/prometheus/additional_metrics_query_result.json58
-rw-r--r--spec/fixtures/api/schemas/public_api/v3/issues.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v3/merge_requests.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/branch.json20
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/branches.json4
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/commit/basic.json37
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/issues.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/merge_requests.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/user/admin.json34
-rw-r--r--spec/fixtures/config/kubeconfig-without-ca.yml18
-rw-r--r--spec/fixtures/config/kubeconfig.yml19
-rw-r--r--spec/fixtures/config/redis_cache_config_with_env.yml2
-rw-r--r--spec/fixtures/config/redis_cache_new_format_host.yml29
-rw-r--r--spec/fixtures/config/redis_cache_new_format_socket.yml6
-rw-r--r--spec/fixtures/config/redis_cache_old_format_host.yml5
-rw-r--r--spec/fixtures/config/redis_cache_old_format_socket.yml3
-rw-r--r--spec/fixtures/config/redis_new_format_host.yml12
-rw-r--r--spec/fixtures/config/redis_queues_config_with_env.yml2
-rw-r--r--spec/fixtures/config/redis_queues_new_format_host.yml29
-rw-r--r--spec/fixtures/config/redis_queues_new_format_socket.yml6
-rw-r--r--spec/fixtures/config/redis_queues_old_format_host.yml5
-rw-r--r--spec/fixtures/config/redis_queues_old_format_socket.yml3
-rw-r--r--spec/fixtures/config/redis_shared_state_config_with_env.yml2
-rw-r--r--spec/fixtures/config/redis_shared_state_new_format_host.yml29
-rw-r--r--spec/fixtures/config/redis_shared_state_new_format_socket.yml6
-rw-r--r--spec/fixtures/config/redis_shared_state_old_format_host.yml5
-rw-r--r--spec/fixtures/config/redis_shared_state_old_format_socket.yml3
-rw-r--r--spec/fixtures/markdown.md.erb22
-rw-r--r--spec/helpers/application_helper_spec.rb27
-rw-r--r--spec/helpers/auth_helper_spec.rb2
-rw-r--r--spec/helpers/avatars_helper_spec.rb48
-rw-r--r--spec/helpers/award_emoji_helper_spec.rb4
-rw-r--r--spec/helpers/button_helper_spec.rb65
-rw-r--r--spec/helpers/diff_helper_spec.rb17
-rw-r--r--spec/helpers/emails_helper_spec.rb2
-rw-r--r--spec/helpers/gitlab_routing_helper_spec.rb69
-rw-r--r--spec/helpers/groups_helper_spec.rb15
-rw-r--r--spec/helpers/hooks_helper_spec.rb20
-rw-r--r--spec/helpers/issuables_helper_spec.rb79
-rw-r--r--spec/helpers/issues_helper_spec.rb10
-rw-r--r--spec/helpers/markup_helper_spec.rb12
-rw-r--r--spec/helpers/milestones_helper_spec.rb36
-rw-r--r--spec/helpers/namespaces_helper_spec.rb2
-rw-r--r--spec/helpers/notes_helper_spec.rb14
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/helpers/projects_helper_spec.rb78
-rw-r--r--spec/helpers/submodule_helper_spec.rb5
-rw-r--r--spec/initializers/6_validations_spec.rb2
-rw-r--r--spec/initializers/8_metrics_spec.rb12
-rw-r--r--spec/initializers/secret_token_spec.rb2
-rw-r--r--spec/initializers/settings_spec.rb42
-rw-r--r--spec/initializers/trusted_proxies_spec.rb2
-rw-r--r--spec/javascripts/awards_handler_spec.js15
-rw-r--r--spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js2
-rw-r--r--spec/javascripts/behaviors/quick_submit_spec.js21
-rw-r--r--spec/javascripts/boards/board_new_issue_spec.js203
-rw-r--r--spec/javascripts/boards/list_spec.js37
-rw-r--r--spec/javascripts/close_reopen_report_toggle_spec.js270
-rw-r--r--spec/javascripts/commit/pipelines/pipelines_spec.js35
-rw-r--r--spec/javascripts/emoji_spec.js (renamed from spec/javascripts/gl_emoji_spec.js)7
-rw-r--r--spec/javascripts/environments/environment_actions_spec.js9
-rw-r--r--spec/javascripts/environments/environment_monitoring_spec.js19
-rw-r--r--spec/javascripts/environments/environment_spec.js9
-rw-r--r--spec/javascripts/environments/environment_stop_spec.js9
-rw-r--r--spec/javascripts/environments/environment_terminal_button_spec.js9
-rw-r--r--spec/javascripts/environments/environments_store_spec.js21
-rw-r--r--spec/javascripts/environments/folder/environments_folder_view_spec.js4
-rw-r--r--spec/javascripts/filtered_search/dropdown_user_spec.js41
-rw-r--r--spec/javascripts/filtered_search/filtered_search_manager_spec.js61
-rw-r--r--spec/javascripts/fixtures/merge_requests.rb12
-rw-r--r--spec/javascripts/fixtures/merge_requests_diffs.rb57
-rw-r--r--spec/javascripts/fixtures/oauth_remember_me.html.haml5
-rw-r--r--spec/javascripts/fixtures/prometheus_service.rb30
-rw-r--r--spec/javascripts/fixtures/u2f.rb4
-rw-r--r--spec/javascripts/groups/groups_spec.js24
-rw-r--r--spec/javascripts/helpers/vue_resource_helper.js11
-rw-r--r--spec/javascripts/integrations/integration_settings_form_spec.js4
-rw-r--r--spec/javascripts/issue_show/components/app_spec.js91
-rw-r--r--spec/javascripts/issue_show/components/description_spec.js54
-rw-r--r--spec/javascripts/issue_show/components/fields/description_spec.js20
-rw-r--r--spec/javascripts/issue_show/components/fields/title_spec.js20
-rw-r--r--spec/javascripts/issue_show/helpers.js10
-rw-r--r--spec/javascripts/issue_spec.js65
-rw-r--r--spec/javascripts/lazy_loader_spec.js57
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js1
-rw-r--r--spec/javascripts/lib/utils/dom_utils_spec.js35
-rw-r--r--spec/javascripts/lib/utils/poll_spec.js52
-rw-r--r--spec/javascripts/merge_request_notes_spec.js2
-rw-r--r--spec/javascripts/merge_request_spec.js33
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js151
-rw-r--r--spec/javascripts/monitoring/deployments_spec.js133
-rw-r--r--spec/javascripts/monitoring/mock_data.js4230
-rw-r--r--spec/javascripts/monitoring/monitoring_column_spec.js109
-rw-r--r--spec/javascripts/monitoring/monitoring_deployment_spec.js137
-rw-r--r--spec/javascripts/monitoring/monitoring_flag_spec.js76
-rw-r--r--spec/javascripts/monitoring/monitoring_legends_spec.js111
-rw-r--r--spec/javascripts/monitoring/monitoring_row_spec.js57
-rw-r--r--spec/javascripts/monitoring/monitoring_spec.js49
-rw-r--r--spec/javascripts/monitoring/monitoring_state_spec.js110
-rw-r--r--spec/javascripts/monitoring/monitoring_store_spec.js24
-rw-r--r--spec/javascripts/monitoring/prometheus_graph_spec.js98
-rw-r--r--spec/javascripts/monitoring/prometheus_mock_data.js1014
-rw-r--r--spec/javascripts/notes_spec.js45
-rw-r--r--spec/javascripts/oauth_remember_me_spec.js26
-rw-r--r--spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js5
-rw-r--r--spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js145
-rw-r--r--spec/javascripts/pipelines/stage_spec.js43
-rw-r--r--spec/javascripts/prometheus_metrics/mock_data.js41
-rw-r--r--spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js158
-rw-r--r--spec/javascripts/sidebar/assignee_title_spec.js25
-rw-r--r--spec/javascripts/signin_tabs_memoizer_spec.js17
-rw-r--r--spec/javascripts/test_bundle.js21
-rw-r--r--spec/javascripts/todos_spec.js4
-rw-r--r--spec/javascripts/visibility_select_spec.js4
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js1
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js7
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js2
-rw-r--r--spec/javascripts/vue_shared/components/commit_spec.js4
-rw-r--r--spec/javascripts/vue_shared/components/markdown/field_spec.js105
-rw-r--r--spec/javascripts/vue_shared/components/table_pagination_spec.js302
-rw-r--r--spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js1
-rw-r--r--spec/javascripts/vue_shared/directives/tooltip_spec.js63
-rw-r--r--spec/javascripts/zen_mode_spec.js3
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb2
-rw-r--r--spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/blockquote_fence_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb16
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/emoji_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb11
-rw-r--r--spec/lib/banzai/filter/external_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/gollum_tags_filter_spec.rb6
-rw-r--r--spec/lib/banzai/filter/html_entity_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/image_lazy_load_filter_spec.rb19
-rw-r--r--spec/lib/banzai/filter/image_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/inline_diff_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/issuable_state_filter_spec.rb12
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb27
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb64
-rw-r--r--spec/lib/banzai/filter/markdown_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/math_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb17
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb24
-rw-r--r--spec/lib/banzai/filter/plantuml_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb16
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/table_of_contents_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/video_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/wiki_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb2
-rw-r--r--spec/lib/banzai/issuable_extractor_spec.rb2
-rw-r--r--spec/lib/banzai/pipeline/gfm_pipeline_spec.rb90
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/issue_parser_spec.rb12
-rw-r--r--spec/lib/banzai/reference_parser/label_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/merge_request_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/milestone_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/snippet_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb2
-rw-r--r--spec/lib/ci/ansi2html_spec.rb2
-rw-r--r--spec/lib/ci/charts_spec.rb12
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb87
-rw-r--r--spec/lib/ci/mask_secret_spec.rb2
-rw-r--r--spec/lib/constraints/group_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb2
-rw-r--r--spec/lib/constraints/user_url_constrainer_spec.rb2
-rw-r--r--spec/lib/disable_email_interceptor_spec.rb6
-rw-r--r--spec/lib/event_filter_spec.rb18
-rw-r--r--spec/lib/extracts_path_spec.rb6
-rw-r--r--spec/lib/feature_spec.rb2
-rw-r--r--spec/lib/file_size_validator_spec.rb4
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/unique_ips_limiter_spec.rb2
-rw-r--r--spec/lib/gitlab/auth_spec.rb14
-rw-r--r--spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb19
-rw-r--r--spec/lib/gitlab/background_migration_spec.rb120
-rw-r--r--spec/lib/gitlab/backup/manager_spec.rb54
-rw-r--r--spec/lib/gitlab/backup/repository_spec.rb56
-rw-r--r--spec/lib/gitlab/badge/pipeline/metadata_spec.rb (renamed from spec/lib/gitlab/badge/build/metadata_spec.rb)6
-rw-r--r--spec/lib/gitlab/badge/pipeline/status_spec.rb (renamed from spec/lib/gitlab/badge/build/status_spec.rb)37
-rw-r--r--spec/lib/gitlab/badge/pipeline/template_spec.rb (renamed from spec/lib/gitlab/badge/build/template_spec.rb)18
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/project_creator_spec.rb4
-rw-r--r--spec/lib/gitlab/blame_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb52
-rw-r--r--spec/lib/gitlab/cache/request_cache_spec.rb133
-rw-r--r--spec/lib/gitlab/chat_name_token_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/force_push_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/step_spec.rb49
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb52
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb25
-rw-r--r--spec/lib/gitlab/ci/status/build/retryable_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/stop_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/trace/stream_spec.rb50
-rw-r--r--spec/lib/gitlab/ci_access_spec.rb4
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb10
-rw-r--r--spec/lib/gitlab/color_schemes_spec.rb2
-rw-r--r--spec/lib/gitlab/conflict/file_collection_spec.rb2
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb6
-rw-r--r--spec/lib/gitlab/conflict/parser_spec.rb4
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb17
-rw-r--r--spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/note_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/push_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/wiki_page_spec.rb21
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb82
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb76
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb80
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb78
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb24
-rw-r--r--spec/lib/gitlab/database/sha_attribute_spec.rb33
-rw-r--r--spec/lib/gitlab/database_spec.rb6
-rw-r--r--spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb10
-rw-r--r--spec/lib/gitlab/dependency_linker_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/diff_refs_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb6
-rw-r--r--spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/inline_diff_marker_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/inline_diff_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/line_mapper_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/parallel_diff_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/parser_spec.rb4
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/position_tracer_spec.rb2
-rw-r--r--spec/lib/gitlab/email/attachment_uploader_spec.rb2
-rw-r--r--spec/lib/gitlab/email/handler/create_issue_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/receiver_spec.rb2
-rw-r--r--spec/lib/gitlab/email/reply_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/exclusive_lease_spec.rb15
-rw-r--r--spec/lib/gitlab/fake_application_settings_spec.rb10
-rw-r--r--spec/lib/gitlab/file_finder_spec.rb2
-rw-r--r--spec/lib/gitlab/fogbugz_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/git/blame_spec.rb3
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb24
-rw-r--r--spec/lib/gitlab/git/branch_spec.rb45
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb157
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb2
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb22
-rw-r--r--spec/lib/gitlab/git/hook_spec.rb46
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb475
-rw-r--r--spec/lib/gitlab/git/rev_list_spec.rb6
-rw-r--r--spec/lib/gitlab/git/tag_spec.rb38
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb23
-rw-r--r--spec/lib/gitlab/git_access_spec.rb8
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb4
-rw-r--r--spec/lib/gitlab/git_ref_validator_spec.rb44
-rw-r--r--spec/lib/gitlab/git_spec.rb8
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb123
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_spec.rb85
-rw-r--r--spec/lib/gitlab/gitaly_client/diff_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/notification_service_spec.rb (renamed from spec/lib/gitlab/gitaly_client/notifications_spec.rb)4
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_service_spec.rb (renamed from spec/lib/gitlab/gitaly_client/ref_spec.rb)46
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb19
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb10
-rw-r--r--spec/lib/gitlab/github_import/branch_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/comment_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/issuable_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/issue_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/label_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/milestone_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/pull_request_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/release_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/user_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/wiki_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/gitlab_import/client_spec.rb4
-rw-r--r--spec/lib/gitlab/gitlab_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/gitlab_import/project_creator_spec.rb4
-rw-r--r--spec/lib/gitlab/google_code_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/project_creator_spec.rb4
-rw-r--r--spec/lib/gitlab/gpg/commit_spec.rb127
-rw-r--r--spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb173
-rw-r--r--spec/lib/gitlab/gpg_spec.rb83
-rw-r--r--spec/lib/gitlab/graphs/commits_spec.rb2
-rw-r--r--spec/lib/gitlab/health_checks/fs_shards_check_spec.rb71
-rw-r--r--spec/lib/gitlab/health_checks/redis/cache_check_spec.rb6
-rw-r--r--spec/lib/gitlab/health_checks/redis/queues_check_spec.rb6
-rw-r--r--spec/lib/gitlab/health_checks/redis/redis_check_spec.rb6
-rw-r--r--spec/lib/gitlab/health_checks/redis/shared_state_check_spec.rb6
-rw-r--r--spec/lib/gitlab/health_checks/redis_check_spec.rb6
-rw-r--r--spec/lib/gitlab/health_checks/simple_check_shared.rb10
-rw-r--r--spec/lib/gitlab/highlight_spec.rb6
-rw-r--r--spec/lib/gitlab/i18n_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml10
-rw-r--r--spec/lib/gitlab/import_export/attribute_cleaner_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/attribute_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/avatar_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/avatar_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/file_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/fork_spec.rb8
-rw-r--r--spec/lib/gitlab/import_export/hash_util_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/import_export_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/members_mapper_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/merge_request_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/model_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project.json44
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb6
-rw-r--r--spec/lib/gitlab/import_export/reader_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/relation_factory_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb6
-rw-r--r--spec/lib/gitlab/import_export/repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml15
-rw-r--r--spec/lib/gitlab/import_export/version_checker_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/incoming_email_spec.rb2
-rw-r--r--spec/lib/gitlab/issuable_metadata_spec.rb59
-rw-r--r--spec/lib/gitlab/issuable_sorter_spec.rb2
-rw-r--r--spec/lib/gitlab/key_fingerprint_spec.rb4
-rw-r--r--spec/lib/gitlab/kubernetes_spec.rb24
-rw-r--r--spec/lib/gitlab/lazy_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/access_spec.rb14
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb8
-rw-r--r--spec/lib/gitlab/ldap/auth_hash_spec.rb4
-rw-r--r--spec/lib/gitlab/ldap/authentication_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/config_spec.rb256
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb6
-rw-r--r--spec/lib/gitlab/lfs_token_spec.rb2
-rw-r--r--spec/lib/gitlab/markup_helper_spec.rb14
-rw-r--r--spec/lib/gitlab/metrics/influx_sampler_spec.rb (renamed from spec/lib/gitlab/metrics/sampler_spec.rb)10
-rw-r--r--spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb71
-rw-r--r--spec/lib/gitlab/metrics/unicorn_sampler_spec.rb108
-rw-r--r--spec/lib/gitlab/middleware/go_spec.rb2
-rw-r--r--spec/lib/gitlab/o_auth/auth_hash_spec.rb4
-rw-r--r--spec/lib/gitlab/o_auth/provider_spec.rb2
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb4
-rw-r--r--spec/lib/gitlab/optimistic_locking_spec.rb2
-rw-r--r--spec/lib/gitlab/other_markup_spec.rb2
-rw-r--r--spec/lib/gitlab/path_regex_spec.rb63
-rw-r--r--spec/lib/gitlab/performance_bar_spec.rb92
-rw-r--r--spec/lib/gitlab/polling_interval_spec.rb2
-rw-r--r--spec/lib/gitlab/popen_spec.rb15
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb2
-rw-r--r--spec/lib/gitlab/project_transfer_spec.rb4
-rw-r--r--spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb246
-rw-r--r--spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb25
-rw-r--r--spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb21
-rw-r--r--spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb2
-rw-r--r--spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb134
-rw-r--r--spec/lib/gitlab/prometheus_client_spec.rb32
-rw-r--r--spec/lib/gitlab/quick_actions/dsl_spec.rb16
-rw-r--r--spec/lib/gitlab/quick_actions/extractor_spec.rb37
-rw-r--r--spec/lib/gitlab/quick_actions/substitution_definition_spec.rb42
-rw-r--r--spec/lib/gitlab/redis/cache_spec.rb20
-rw-r--r--spec/lib/gitlab/redis/queues_spec.rb20
-rw-r--r--spec/lib/gitlab/redis/shared_state_spec.rb20
-rw-r--r--spec/lib/gitlab/redis/wrapper_spec.rb20
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb35
-rw-r--r--spec/lib/gitlab/regex_spec.rb19
-rw-r--r--spec/lib/gitlab/request_context_spec.rb6
-rw-r--r--spec/lib/gitlab/request_forgery_protection_spec.rb89
-rw-r--r--spec/lib/gitlab/request_profiler_spec.rb2
-rw-r--r--spec/lib/gitlab/route_map_spec.rb15
-rw-r--r--spec/lib/gitlab/saml/user_spec.rb2
-rw-r--r--spec/lib/gitlab/shell_spec.rb97
-rw-r--r--spec/lib/gitlab/sherlock/collection_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/file_sample_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/line_profiler_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/line_sample_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/location_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/middleware_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/query_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/transaction_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_status_spec.rb12
-rw-r--r--spec/lib/gitlab/slash_commands/command_spec.rb4
-rw-r--r--spec/lib/gitlab/slash_commands/deploy_spec.rb58
-rw-r--r--spec/lib/gitlab/slash_commands/issue_new_spec.rb2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_search_spec.rb2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_show_spec.rb2
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb20
-rw-r--r--spec/lib/gitlab/sql/glob_spec.rb53
-rw-r--r--spec/lib/gitlab/sql/union_spec.rb2
-rw-r--r--spec/lib/gitlab/string_range_marker_spec.rb2
-rw-r--r--spec/lib/gitlab/string_regex_marker_spec.rb2
-rw-r--r--spec/lib/gitlab/untrusted_regexp_spec.rb98
-rw-r--r--spec/lib/gitlab/upgrader_spec.rb4
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb2
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb34
-rw-r--r--spec/lib/gitlab/user_access_spec.rb6
-rw-r--r--spec/lib/gitlab/user_activities_spec.rb34
-rw-r--r--spec/lib/gitlab/utils_spec.rb2
-rw-r--r--spec/lib/gitlab/version_info_spec.rb2
-rw-r--r--spec/lib/gitlab/visibility_level_spec.rb8
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb52
-rw-r--r--spec/lib/gitlab_spec.rb2
-rw-r--r--spec/lib/repository_cache_spec.rb4
-rw-r--r--spec/lib/system_check/simple_executor_spec.rb26
-rw-r--r--spec/lib/system_check_spec.rb4
-rw-r--r--spec/mailers/emails/profile_spec.rb30
-rw-r--r--spec/mailers/notify_spec.rb43
-rw-r--r--spec/migrations/add_foreign_key_to_merge_requests_spec.rb39
-rw-r--r--spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb2
-rw-r--r--spec/migrations/clean_appearance_symlinks_spec.rb46
-rw-r--r--spec/migrations/clean_stage_id_reference_migration_spec.rb34
-rw-r--r--spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb35
-rw-r--r--spec/migrations/migrate_process_commit_worker_jobs_spec.rb4
-rw-r--r--spec/migrations/migrate_stage_id_reference_in_background_spec.rb68
-rw-r--r--spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb4
-rw-r--r--spec/migrations/migrate_user_project_view_spec.rb2
-rw-r--r--spec/migrations/move_personal_snippets_files_spec.rb180
-rw-r--r--spec/migrations/move_system_upload_folder_spec.rb62
-rw-r--r--spec/migrations/rename_duplicated_variable_key_spec.rb34
-rw-r--r--spec/models/ability_spec.rb21
-rw-r--r--spec/models/abuse_report_spec.rb2
-rw-r--r--spec/models/appearance_spec.rb2
-rw-r--r--spec/models/application_setting_spec.rb170
-rw-r--r--spec/models/award_emoji_spec.rb2
-rw-r--r--spec/models/blob_viewer/base_spec.rb2
-rw-r--r--spec/models/blob_viewer/changelog_spec.rb2
-rw-r--r--spec/models/blob_viewer/composer_json_spec.rb2
-rw-r--r--spec/models/blob_viewer/gemspec_spec.rb2
-rw-r--r--spec/models/blob_viewer/gitlab_ci_yml_spec.rb2
-rw-r--r--spec/models/blob_viewer/license_spec.rb2
-rw-r--r--spec/models/blob_viewer/package_json_spec.rb2
-rw-r--r--spec/models/blob_viewer/podspec_json_spec.rb2
-rw-r--r--spec/models/blob_viewer/podspec_spec.rb2
-rw-r--r--spec/models/blob_viewer/readme_spec.rb49
-rw-r--r--spec/models/blob_viewer/route_map_spec.rb2
-rw-r--r--spec/models/blob_viewer/server_side_spec.rb2
-rw-r--r--spec/models/broadcast_message_spec.rb10
-rw-r--r--spec/models/chat_name_spec.rb2
-rw-r--r--spec/models/chat_team_spec.rb2
-rw-r--r--spec/models/ci/artifact_blob_spec.rb2
-rw-r--r--spec/models/ci/build_spec.rb200
-rw-r--r--spec/models/ci/group_spec.rb2
-rw-r--r--spec/models/ci/group_variable_spec.rb31
-rw-r--r--spec/models/ci/legacy_stage_spec.rb2
-rw-r--r--spec/models/ci/pipeline_schedule_spec.rb23
-rw-r--r--spec/models/ci/pipeline_schedule_variable_spec.rb7
-rw-r--r--spec/models/ci/pipeline_spec.rb46
-rw-r--r--spec/models/ci/pipeline_variable_spec.rb8
-rw-r--r--spec/models/ci/runner_spec.rb30
-rw-r--r--spec/models/ci/trigger_spec.rb2
-rw-r--r--spec/models/ci/variable_spec.rb47
-rw-r--r--spec/models/commit_range_spec.rb2
-rw-r--r--spec/models/commit_spec.rb10
-rw-r--r--spec/models/commit_status_spec.rb37
-rw-r--r--spec/models/compare_spec.rb2
-rw-r--r--spec/models/concerns/case_sensitivity_spec.rb2
-rw-r--r--spec/models/concerns/discussion_on_diff_spec.rb2
-rw-r--r--spec/models/concerns/each_batch_spec.rb53
-rw-r--r--spec/models/concerns/feature_gate_spec.rb19
-rw-r--r--spec/models/concerns/has_status_spec.rb2
-rw-r--r--spec/models/concerns/has_variable_spec.rb43
-rw-r--r--spec/models/concerns/issuable_spec.rb2
-rw-r--r--spec/models/concerns/mentionable_spec.rb18
-rw-r--r--spec/models/concerns/noteable_spec.rb2
-rw-r--r--spec/models/concerns/participable_spec.rb2
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb2
-rw-r--r--spec/models/concerns/resolvable_discussion_spec.rb2
-rw-r--r--spec/models/concerns/resolvable_note_spec.rb2
-rw-r--r--spec/models/concerns/routable_spec.rb13
-rw-r--r--spec/models/concerns/sha_attribute_spec.rb46
-rw-r--r--spec/models/concerns/uniquify_spec.rb2
-rw-r--r--spec/models/cycle_analytics/code_spec.rb2
-rw-r--r--spec/models/cycle_analytics/issue_spec.rb2
-rw-r--r--spec/models/cycle_analytics/plan_spec.rb2
-rw-r--r--spec/models/cycle_analytics/production_spec.rb2
-rw-r--r--spec/models/cycle_analytics/review_spec.rb2
-rw-r--r--spec/models/cycle_analytics/staging_spec.rb2
-rw-r--r--spec/models/cycle_analytics/test_spec.rb2
-rw-r--r--spec/models/deploy_key_spec.rb2
-rw-r--r--spec/models/deploy_keys_project_spec.rb2
-rw-r--r--spec/models/deployment_spec.rb34
-rw-r--r--spec/models/diff_discussion_spec.rb2
-rw-r--r--spec/models/diff_note_spec.rb2
-rw-r--r--spec/models/diff_viewer/base_spec.rb2
-rw-r--r--spec/models/diff_viewer/server_side_spec.rb2
-rw-r--r--spec/models/discussion_spec.rb2
-rw-r--r--spec/models/email_spec.rb2
-rw-r--r--spec/models/environment_spec.rb122
-rw-r--r--spec/models/event_spec.rb2
-rw-r--r--spec/models/external_issue_spec.rb2
-rw-r--r--spec/models/forked_project_link_spec.rb76
-rw-r--r--spec/models/generic_commit_status_spec.rb2
-rw-r--r--spec/models/global_milestone_spec.rb16
-rw-r--r--spec/models/gpg_key_spec.rb157
-rw-r--r--spec/models/gpg_signature_spec.rb28
-rw-r--r--spec/models/group_label_spec.rb2
-rw-r--r--spec/models/group_milestone_spec.rb6
-rw-r--r--spec/models/group_spec.rb76
-rw-r--r--spec/models/guest_spec.rb12
-rw-r--r--spec/models/hooks/project_hook_spec.rb12
-rw-r--r--spec/models/hooks/service_hook_spec.rb6
-rw-r--r--spec/models/hooks/system_hook_spec.rb7
-rw-r--r--spec/models/hooks/web_hook_log_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb2
-rw-r--r--spec/models/identity_spec.rb2
-rw-r--r--spec/models/issue/metrics_spec.rb2
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/key_spec.rb2
-rw-r--r--spec/models/label_link_spec.rb2
-rw-r--r--spec/models/label_priority_spec.rb2
-rw-r--r--spec/models/label_spec.rb2
-rw-r--r--spec/models/legacy_diff_discussion_spec.rb2
-rw-r--r--spec/models/lfs_objects_project_spec.rb2
-rw-r--r--spec/models/list_spec.rb6
-rw-r--r--spec/models/member_spec.rb4
-rw-r--r--spec/models/members/group_member_spec.rb2
-rw-r--r--spec/models/members/project_member_spec.rb4
-rw-r--r--spec/models/merge_request/metrics_spec.rb2
-rw-r--r--spec/models/merge_request_diff_commit_spec.rb15
-rw-r--r--spec/models/merge_request_diff_file_spec.rb29
-rw-r--r--spec/models/merge_request_diff_spec.rb17
-rw-r--r--spec/models/merge_request_spec.rb126
-rw-r--r--spec/models/milestone_spec.rb48
-rw-r--r--spec/models/namespace_spec.rb60
-rw-r--r--spec/models/network/graph_spec.rb2
-rw-r--r--spec/models/note_spec.rb4
-rw-r--r--spec/models/notification_setting_spec.rb15
-rw-r--r--spec/models/pages_domain_spec.rb4
-rw-r--r--spec/models/personal_access_token_spec.rb2
-rw-r--r--spec/models/project_group_link_spec.rb12
-rw-r--r--spec/models/project_label_spec.rb2
-rw-r--r--spec/models/project_services/asana_service_spec.rb4
-rw-r--r--spec/models/project_services/assembla_service_spec.rb4
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb6
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb2
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb2
-rw-r--r--spec/models/project_services/campfire_service_spec.rb15
-rw-r--r--spec/models/project_services/chat_message/issue_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/merge_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/note_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/push_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_message/wiki_page_message_spec.rb2
-rw-r--r--spec/models/project_services/chat_notification_service_spec.rb2
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb2
-rw-r--r--spec/models/project_services/external_wiki_service_spec.rb6
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb4
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb4
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb29
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb4
-rw-r--r--spec/models/project_services/irker_service_spec.rb4
-rw-r--r--spec/models/project_services/issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb75
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb50
-rw-r--r--spec/models/project_services/mattermost_service_spec.rb2
-rw-r--r--spec/models/project_services/mattermost_slash_commands_service_spec.rb2
-rw-r--r--spec/models/project_services/microsoft_teams_service_spec.rb4
-rw-r--r--spec/models/project_services/pivotaltracker_service_spec.rb4
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb12
-rw-r--r--spec/models/project_services/pushover_service_spec.rb4
-rw-r--r--spec/models/project_services/redmine_service_spec.rb6
-rw-r--r--spec/models/project_services/slack_service_spec.rb2
-rw-r--r--spec/models/project_services/slack_slash_commands_service_spec.rb2
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb8
-rw-r--r--spec/models/project_snippet_spec.rb2
-rw-r--r--spec/models/project_spec.rb345
-rw-r--r--spec/models/project_statistics_spec.rb2
-rw-r--r--spec/models/project_team_spec.rb2
-rw-r--r--spec/models/project_wiki_spec.rb22
-rw-r--r--spec/models/protectable_dropdown_spec.rb2
-rw-r--r--spec/models/protected_branch/merge_access_level_spec.rb2
-rw-r--r--spec/models/protected_branch/push_access_level_spec.rb2
-rw-r--r--spec/models/protected_branch_spec.rb38
-rw-r--r--spec/models/protected_tag_spec.rb2
-rw-r--r--spec/models/redirect_route_spec.rb6
-rw-r--r--spec/models/release_spec.rb2
-rw-r--r--spec/models/repository_spec.rb62
-rw-r--r--spec/models/route_spec.rb8
-rw-r--r--spec/models/sent_notification_spec.rb6
-rw-r--r--spec/models/service_spec.rb2
-rw-r--r--spec/models/snippet_blob_spec.rb2
-rw-r--r--spec/models/snippet_spec.rb2
-rw-r--r--spec/models/spam_log_spec.rb2
-rw-r--r--spec/models/subscription_spec.rb2
-rw-r--r--spec/models/system_note_metadata_spec.rb2
-rw-r--r--spec/models/timelog_spec.rb2
-rw-r--r--spec/models/todo_spec.rb2
-rw-r--r--spec/models/tree_spec.rb2
-rw-r--r--spec/models/upload_spec.rb2
-rw-r--r--spec/models/user_agent_detail_spec.rb2
-rw-r--r--spec/models/user_spec.rb265
-rw-r--r--spec/models/wiki_directory_spec.rb6
-rw-r--r--spec/models/wiki_page_spec.rb52
-rw-r--r--spec/policies/base_policy_spec.rb8
-rw-r--r--spec/policies/ci/build_policy_spec.rb82
-rw-r--r--spec/policies/ci/pipeline_policy_spec.rb66
-rw-r--r--spec/policies/ci/trigger_policy_spec.rb16
-rw-r--r--spec/policies/deploy_key_policy_spec.rb14
-rw-r--r--spec/policies/environment_policy_spec.rb12
-rw-r--r--spec/policies/global_policy_spec.rb54
-rw-r--r--spec/policies/group_policy_spec.rb118
-rw-r--r--spec/policies/issue_policy_spec.rb124
-rw-r--r--spec/policies/personal_snippet_policy_spec.rb70
-rw-r--r--spec/policies/project_policy_spec.rb159
-rw-r--r--spec/policies/project_snippet_policy_spec.rb66
-rw-r--r--spec/policies/user_policy_spec.rb14
-rw-r--r--spec/presenters/ci/build_presenter_spec.rb4
-rw-r--r--spec/presenters/ci/group_variable_presenter_spec.rb63
-rw-r--r--spec/presenters/ci/variable_presenter_spec.rb63
-rw-r--r--spec/presenters/merge_request_presenter_spec.rb41
-rw-r--r--spec/requests/api/branches_spec.rb508
-rw-r--r--spec/requests/api/commit_statuses_spec.rb49
-rw-r--r--spec/requests/api/events_spec.rb2
-rw-r--r--spec/requests/api/features_spec.rb192
-rw-r--r--spec/requests/api/group_milestones_spec.rb21
-rw-r--r--spec/requests/api/groups_spec.rb2
-rw-r--r--spec/requests/api/helpers_spec.rb55
-rw-r--r--spec/requests/api/internal_spec.rb107
-rw-r--r--spec/requests/api/issues_spec.rb75
-rw-r--r--spec/requests/api/jobs_spec.rb2
-rw-r--r--spec/requests/api/merge_requests_spec.rb149
-rw-r--r--spec/requests/api/namespaces_spec.rb35
-rw-r--r--spec/requests/api/pipeline_schedules_spec.rb2
-rw-r--r--spec/requests/api/project_milestones_spec.rb25
-rw-r--r--spec/requests/api/project_snippets_spec.rb24
-rw-r--r--spec/requests/api/projects_spec.rb129
-rw-r--r--spec/requests/api/runner_spec.rb3
-rw-r--r--spec/requests/api/settings_spec.rb11
-rw-r--r--spec/requests/api/snippets_spec.rb21
-rw-r--r--spec/requests/api/todos_spec.rb2
-rw-r--r--spec/requests/api/triggers_spec.rb17
-rw-r--r--spec/requests/api/users_spec.rb175
-rw-r--r--spec/requests/api/v3/groups_spec.rb2
-rw-r--r--spec/requests/api/v3/issues_spec.rb2
-rw-r--r--spec/requests/api/v3/project_hooks_spec.rb6
-rw-r--r--spec/requests/api/v3/projects_spec.rb35
-rw-r--r--spec/requests/api/v3/settings_spec.rb6
-rw-r--r--spec/requests/api/v3/triggers_spec.rb3
-rw-r--r--spec/requests/api/v3/users_spec.rb23
-rw-r--r--spec/requests/api/variables_spec.rb11
-rw-r--r--spec/requests/api/version_spec.rb4
-rw-r--r--spec/requests/ci/api/builds_spec.rb66
-rw-r--r--spec/requests/ci/api/triggers_spec.rb14
-rw-r--r--spec/requests/git_http_spec.rb6
-rw-r--r--spec/requests/jwt_controller_spec.rb2
-rw-r--r--spec/requests/openid_connect_spec.rb4
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb24
-rw-r--r--spec/routing/environments_spec.rb2
-rw-r--r--spec/routing/project_routing_spec.rb95
-rw-r--r--spec/rubocop/cop/active_record_dependent_spec.rb33
-rw-r--r--spec/rubocop/cop/active_record_serialize_spec.rb (renamed from spec/rubocop/cop/activerecord_serialize_spec.rb)4
-rw-r--r--spec/rubocop/cop/in_batches_spec.rb19
-rw-r--r--spec/rubocop/cop/migration/hash_index_spec.rb53
-rw-r--r--spec/rubocop/cop/project_path_helper_spec.rb41
-rw-r--r--spec/serializers/build_details_entity_spec.rb89
-rw-r--r--spec/serializers/deploy_key_entity_spec.rb6
-rw-r--r--spec/serializers/job_entity_spec.rb11
-rw-r--r--spec/serializers/merge_request_entity_spec.rb2
-rw-r--r--spec/serializers/pipeline_details_entity_spec.rb6
-rw-r--r--spec/serializers/pipeline_entity_spec.rb4
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb33
-rw-r--r--spec/services/access_token_validation_service_spec.rb45
-rw-r--r--spec/services/after_branch_delete_service_spec.rb2
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb2
-rw-r--r--spec/services/boards/create_service_spec.rb4
-rw-r--r--spec/services/boards/issues/create_service_spec.rb2
-rw-r--r--spec/services/boards/issues/list_service_spec.rb6
-rw-r--r--spec/services/boards/issues/move_service_spec.rb4
-rw-r--r--spec/services/boards/list_service_spec.rb2
-rw-r--r--spec/services/boards/lists/create_service_spec.rb2
-rw-r--r--spec/services/boards/lists/destroy_service_spec.rb2
-rw-r--r--spec/services/boards/lists/generate_service_spec.rb2
-rw-r--r--spec/services/boards/lists/list_service_spec.rb2
-rw-r--r--spec/services/boards/lists/move_service_spec.rb2
-rw-r--r--spec/services/chat_names/authorize_user_service_spec.rb2
-rw-r--r--spec/services/chat_names/find_user_service_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb233
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb26
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb83
-rw-r--r--spec/services/ci/play_build_service_spec.rb2
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb37
-rw-r--r--spec/services/ci/register_job_service_spec.rb2
-rw-r--r--spec/services/ci/retry_build_service_spec.rb6
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb22
-rw-r--r--spec/services/ci/stop_environments_service_spec.rb2
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb2
-rw-r--r--spec/services/ci/update_runner_service_spec.rb2
-rw-r--r--spec/services/compare_service_spec.rb2
-rw-r--r--spec/services/create_branch_service_spec.rb2
-rw-r--r--spec/services/create_deployment_service_spec.rb4
-rw-r--r--spec/services/create_release_service_spec.rb4
-rw-r--r--spec/services/create_snippet_service_spec.rb2
-rw-r--r--spec/services/delete_branch_service_spec.rb2
-rw-r--r--spec/services/delete_merged_branches_service_spec.rb12
-rw-r--r--spec/services/discussions/update_diff_position_service_spec.rb2
-rw-r--r--spec/services/emails/create_service_spec.rb21
-rw-r--r--spec/services/emails/destroy_service_spec.rb14
-rw-r--r--spec/services/event_create_service_spec.rb6
-rw-r--r--spec/services/git_hooks_service_spec.rb11
-rw-r--r--spec/services/git_push_service_spec.rb283
-rw-r--r--spec/services/git_tag_push_service_spec.rb6
-rw-r--r--spec/services/gravatar_service_spec.rb2
-rw-r--r--spec/services/groups/create_service_spec.rb2
-rw-r--r--spec/services/groups/destroy_service_spec.rb66
-rw-r--r--spec/services/groups/update_service_spec.rb2
-rw-r--r--spec/services/import_export_clean_up_service_spec.rb2
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb2
-rw-r--r--spec/services/issues/build_service_spec.rb2
-rw-r--r--spec/services/issues/close_service_spec.rb10
-rw-r--r--spec/services/issues/create_service_spec.rb2
-rw-r--r--spec/services/issues/duplicate_service_spec.rb80
-rw-r--r--spec/services/issues/move_service_spec.rb67
-rw-r--r--spec/services/issues/reopen_service_spec.rb2
-rw-r--r--spec/services/issues/resolve_discussions_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb31
-rw-r--r--spec/services/labels/create_service_spec.rb38
-rw-r--r--spec/services/labels/find_or_create_service_spec.rb2
-rw-r--r--spec/services/labels/promote_service_spec.rb2
-rw-r--r--spec/services/labels/transfer_service_spec.rb2
-rw-r--r--spec/services/labels/update_service_spec.rb14
-rw-r--r--spec/services/members/approve_access_request_service_spec.rb2
-rw-r--r--spec/services/members/authorized_destroy_service_spec.rb2
-rw-r--r--spec/services/members/create_service_spec.rb2
-rw-r--r--spec/services/members/destroy_service_spec.rb2
-rw-r--r--spec/services/members/request_access_service_spec.rb2
-rw-r--r--spec/services/merge_requests/assign_issues_service_spec.rb2
-rw-r--r--spec/services/merge_requests/build_service_spec.rb6
-rw-r--r--spec/services/merge_requests/close_service_spec.rb2
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb2
-rw-r--r--spec/services/merge_requests/create_service_spec.rb2
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb77
-rw-r--r--spec/services/merge_requests/post_merge_service_spec.rb2
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb58
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb4
-rw-r--r--spec/services/merge_requests/resolved_discussion_notification_service_spec.rb2
-rw-r--r--spec/services/merge_requests/update_service_spec.rb22
-rw-r--r--spec/services/milestones/close_service_spec.rb4
-rw-r--r--spec/services/milestones/create_service_spec.rb4
-rw-r--r--spec/services/milestones/destroy_service_spec.rb51
-rw-r--r--spec/services/note_summary_spec.rb2
-rw-r--r--spec/services/notes/build_service_spec.rb2
-rw-r--r--spec/services/notes/create_service_spec.rb2
-rw-r--r--spec/services/notes/destroy_service_spec.rb2
-rw-r--r--spec/services/notes/post_process_service_spec.rb4
-rw-r--r--spec/services/notes/quick_actions_service_spec.rb2
-rw-r--r--spec/services/notes/update_service_spec.rb2
-rw-r--r--spec/services/notification_recipient_service_spec.rb34
-rw-r--r--spec/services/notification_service_spec.rb65
-rw-r--r--spec/services/pages_service_spec.rb4
-rw-r--r--spec/services/projects/autocomplete_service_spec.rb2
-rw-r--r--spec/services/projects/create_service_spec.rb2
-rw-r--r--spec/services/projects/destroy_service_spec.rb85
-rw-r--r--spec/services/projects/download_service_spec.rb2
-rw-r--r--spec/services/projects/enable_deploy_key_service_spec.rb2
-rw-r--r--spec/services/projects/fork_service_spec.rb2
-rw-r--r--spec/services/projects/import_service_spec.rb2
-rw-r--r--spec/services/projects/participants_service_spec.rb6
-rw-r--r--spec/services/projects/propagate_service_template_spec.rb2
-rw-r--r--spec/services/projects/transfer_service_spec.rb28
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb4
-rw-r--r--spec/services/projects/update_pages_configuration_service_spec.rb2
-rw-r--r--spec/services/projects/update_pages_service_spec.rb72
-rw-r--r--spec/services/projects/update_service_spec.rb57
-rw-r--r--spec/services/protected_branches/create_service_spec.rb2
-rw-r--r--spec/services/protected_branches/update_service_spec.rb2
-rw-r--r--spec/services/protected_tags/create_service_spec.rb2
-rw-r--r--spec/services/protected_tags/update_service_spec.rb2
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb113
-rw-r--r--spec/services/repair_ldap_blocked_user_service_spec.rb4
-rw-r--r--spec/services/repository_archive_clean_up_service_spec.rb2
-rw-r--r--spec/services/search/global_service_spec.rb10
-rw-r--r--spec/services/search/group_service_spec.rb4
-rw-r--r--spec/services/search/snippet_service_spec.rb2
-rw-r--r--spec/services/search_service_spec.rb58
-rw-r--r--spec/services/spam_service_spec.rb2
-rw-r--r--spec/services/system_hooks_service_spec.rb2
-rw-r--r--spec/services/system_note_service_spec.rb62
-rw-r--r--spec/services/tags/create_service_spec.rb2
-rw-r--r--spec/services/tags/destroy_service_spec.rb2
-rw-r--r--spec/services/test_hook_service_spec.rb14
-rw-r--r--spec/services/test_hooks/project_service_spec.rb188
-rw-r--r--spec/services/test_hooks/system_service_spec.rb82
-rw-r--r--spec/services/todo_service_spec.rb22
-rw-r--r--spec/services/update_release_service_spec.rb4
-rw-r--r--spec/services/update_snippet_service_spec.rb2
-rw-r--r--spec/services/upload_service_spec.rb2
-rw-r--r--spec/services/users/activity_service_spec.rb4
-rw-r--r--spec/services/users/build_service_spec.rb2
-rw-r--r--spec/services/users/create_service_spec.rb2
-rw-r--r--spec/services/users/destroy_service_spec.rb2
-rw-r--r--spec/services/users/migrate_to_ghost_user_service_spec.rb33
-rw-r--r--spec/services/users/refresh_authorized_projects_service_spec.rb2
-rw-r--r--spec/services/users/update_service_spec.rb43
-rw-r--r--spec/services/web_hook_service_spec.rb16
-rw-r--r--spec/services/wiki_pages/create_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/destroy_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/update_service_spec.rb2
-rw-r--r--spec/spec_helper.rb39
-rw-r--r--spec/support/api/milestones_shared_examples.rb (renamed from spec/requests/api/milestones_spec.rb)190
-rw-r--r--spec/support/api/schema_matcher.rb21
-rw-r--r--spec/support/api/scopes/read_user_shared_examples.rb79
-rw-r--r--spec/support/api_helpers.rb18
-rw-r--r--spec/support/capybara.rb12
-rw-r--r--spec/support/capybara_helpers.rb5
-rw-r--r--spec/support/cycle_analytics_helpers.rb4
-rw-r--r--spec/support/devise_helpers.rb14
-rw-r--r--spec/support/dropzone_helper.rb19
-rw-r--r--spec/support/fake_migration_classes.rb8
-rw-r--r--spec/support/features/issuable_slash_commands_shared_examples.rb41
-rw-r--r--spec/support/features/rss_shared_examples.rb4
-rw-r--r--spec/support/filter_item_select_helper.rb19
-rw-r--r--spec/support/filtered_search_helpers.rb3
-rw-r--r--spec/support/forgery_protection.rb11
-rwxr-xr-xspec/support/generate-seed-repo-rb2
-rw-r--r--spec/support/gitaly.rb10
-rw-r--r--spec/support/gitlab-git-test.git/HEAD1
-rw-r--r--spec/support/gitlab-git-test.git/README.md16
-rw-r--r--spec/support/gitlab-git-test.git/config7
-rw-r--r--spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idxbin0 -> 5496 bytes
-rw-r--r--spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.packbin0 -> 381502 bytes
-rw-r--r--spec/support/gitlab-git-test.git/packed-refs18
-rw-r--r--spec/support/gitlab-git-test.git/refs/heads/.gitkeep0
-rw-r--r--spec/support/gitlab-git-test.git/refs/tags/.gitkeep0
-rw-r--r--spec/support/gpg_helpers.rb202
-rw-r--r--spec/support/issuable_shared_examples.rb31
-rw-r--r--spec/support/issue_helpers.rb2
-rw-r--r--spec/support/issue_tracker_service_shared_example.rb8
-rw-r--r--spec/support/jira_service_helper.rb2
-rw-r--r--spec/support/json_response_helpers.rb2
-rw-r--r--spec/support/login_helpers.rb47
-rw-r--r--spec/support/malicious_regexp_shared_examples.rb8
-rw-r--r--spec/support/matchers/access_matchers_for_controller.rb108
-rw-r--r--spec/support/matchers/be_utf8.rb9
-rw-r--r--spec/support/matchers/have_gitlab_http_status.rb14
-rw-r--r--spec/support/matchers/markdown_matchers.rb4
-rw-r--r--spec/support/merge_request_helpers.rb2
-rwxr-xr-xspec/support/prepare-gitlab-git-test-for-commit17
-rw-r--r--spec/support/prometheus/additional_metrics_shared_examples.rb101
-rw-r--r--spec/support/prometheus/metric_builders.rb27
-rw-r--r--spec/support/prometheus_helpers.rb59
-rw-r--r--spec/support/protected_tags/access_control_ce_shared_examples.rb4
-rw-r--r--spec/support/redis/redis_shared_examples.rb (renamed from spec/lib/gitlab/redis_spec.rb)82
-rw-r--r--spec/support/routing_helpers.rb3
-rw-r--r--spec/support/seed_helper.rb2
-rw-r--r--spec/support/services/migrate_to_ghost_user_service_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/features/protected_branches_access_control_ce.rb (renamed from spec/support/protected_branches/access_control_ce_shared_examples.rb)14
-rw-r--r--spec/support/shared_examples/requests/api/status_shared_examples.rb (renamed from spec/support/api/status_shared_examples.rb)6
-rw-r--r--spec/support/sidekiq.rb10
-rw-r--r--spec/support/slack_mattermost_notifications_shared_examples.rb2
-rw-r--r--spec/support/sorting_helper.rb18
-rw-r--r--spec/support/stub_configuration.rb34
-rw-r--r--spec/support/stub_env.rb32
-rw-r--r--spec/support/stub_feature_flags.rb8
-rw-r--r--spec/support/test_env.rb28
-rw-r--r--spec/support/unique_ip_check_shared_examples.rb4
-rwxr-xr-xspec/support/unpack-gitlab-git-test38
-rw-r--r--spec/tasks/gitlab/task_helpers_spec.rb15
-rw-r--r--spec/uploaders/attachment_uploader_spec.rb2
-rw-r--r--spec/uploaders/avatar_uploader_spec.rb2
-rw-r--r--spec/uploaders/file_mover_spec.rb14
-rw-r--r--spec/uploaders/personal_file_uploader_spec.rb4
-rw-r--r--spec/views/ci/status/_badge.html.haml_spec.rb5
-rw-r--r--spec/views/projects/_home_panel.html.haml_spec.rb2
-rw-r--r--spec/views/projects/blob/_viewer.html.haml_spec.rb2
-rw-r--r--spec/views/projects/commit/_commit_box.html.haml_spec.rb2
-rw-r--r--spec/views/projects/commit/show.html.haml_spec.rb10
-rw-r--r--spec/views/projects/diffs/_viewer.html.haml_spec.rb2
-rw-r--r--spec/views/projects/jobs/show.html.haml_spec.rb2
-rw-r--r--spec/views/projects/merge_requests/_commits.html.haml_spec.rb7
-rw-r--r--spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb (renamed from spec/views/projects/merge_requests/_new_submit.html.haml_spec.rb)2
-rw-r--r--spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb2
-rw-r--r--spec/views/projects/pipelines/_stage.html.haml_spec.rb2
-rw-r--r--spec/views/projects/registry/repositories/index.html.haml_spec.rb2
-rw-r--r--spec/views/projects/tags/index.html.haml_spec.rb2
-rw-r--r--spec/views/shared/projects/_project.html.haml_spec.rb19
-rw-r--r--spec/workers/background_migration_worker_spec.rb33
-rw-r--r--spec/workers/create_gpg_signature_worker_spec.rb47
-rw-r--r--spec/workers/expire_build_instance_artifacts_worker_spec.rb14
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb52
-rw-r--r--spec/workers/invalid_gpg_signature_update_worker_spec.rb29
-rw-r--r--spec/workers/post_receive_spec.rb39
-rw-r--r--spec/workers/project_destroy_worker_spec.rb20
-rw-r--r--spec/workers/schedule_update_user_activity_worker_spec.rb2
-rw-r--r--spec/workers/update_user_activity_worker_spec.rb4
1351 files changed, 28925 insertions, 8896 deletions
diff --git a/spec/config/mail_room_spec.rb b/spec/config/mail_room_spec.rb
index 092048a6259..a31e44fa928 100644
--- a/spec/config/mail_room_spec.rb
+++ b/spec/config/mail_room_spec.rb
@@ -5,12 +5,12 @@ describe 'mail_room.yml' do
let(:mailroom_config_path) { 'config/mail_room.yml' }
let(:gitlab_config_path) { 'config/mail_room.yml' }
- let(:redis_config_path) { 'config/resque.yml' }
+ let(:queues_config_path) { 'config/redis.queues.yml' }
let(:configuration) do
vars = {
'MAIL_ROOM_GITLAB_CONFIG_FILE' => absolute_path(gitlab_config_path),
- 'GITLAB_REDIS_CONFIG_FILE' => absolute_path(redis_config_path)
+ 'GITLAB_REDIS_QUEUES_CONFIG_FILE' => absolute_path(queues_config_path)
}
cmd = "puts ERB.new(File.read(#{absolute_path(mailroom_config_path).inspect})).result"
@@ -21,12 +21,12 @@ describe 'mail_room.yml' do
end
before(:each) do
- stub_env('GITLAB_REDIS_CONFIG_FILE', absolute_path(redis_config_path))
- clear_redis_raw_config
+ stub_env('GITLAB_REDIS_QUEUES_CONFIG_FILE', absolute_path(queues_config_path))
+ clear_queues_raw_config
end
after(:each) do
- clear_redis_raw_config
+ clear_queues_raw_config
end
context 'when incoming email is disabled' do
@@ -39,9 +39,9 @@ describe 'mail_room.yml' do
context 'when incoming email is enabled' do
let(:gitlab_config_path) { 'spec/fixtures/config/mail_room_enabled.yml' }
- let(:redis_config_path) { 'spec/fixtures/config/redis_new_format_host.yml' }
+ let(:queues_config_path) { 'spec/fixtures/config/redis_queues_new_format_host.yml' }
- let(:gitlab_redis) { Gitlab::Redis.new(Rails.env) }
+ let(:gitlab_redis_queues) { Gitlab::Redis::Queues.new(Rails.env) }
it 'contains the intended configuration' do
expect(configuration[:mailboxes].length).to eq(1)
@@ -56,8 +56,8 @@ describe 'mail_room.yml' do
expect(mailbox[:name]).to eq('inbox')
expect(mailbox[:idle_timeout]).to eq(60)
- redis_url = gitlab_redis.url
- sentinels = gitlab_redis.sentinels
+ redis_url = gitlab_redis_queues.url
+ sentinels = gitlab_redis_queues.sentinels
expect(mailbox[:delivery_options][:redis_url]).to be_present
expect(mailbox[:delivery_options][:redis_url]).to eq(redis_url)
@@ -73,8 +73,8 @@ describe 'mail_room.yml' do
end
end
- def clear_redis_raw_config
- Gitlab::Redis.remove_instance_variable(:@_raw_config)
+ def clear_queues_raw_config
+ Gitlab::Redis::Queues.remove_instance_variable(:@_raw_config)
rescue NameError
# raised if @_raw_config was not set; ignore
end
diff --git a/spec/controllers/abuse_reports_controller_spec.rb b/spec/controllers/abuse_reports_controller_spec.rb
index 80a418feb3e..ada011e7595 100644
--- a/spec/controllers/abuse_reports_controller_spec.rb
+++ b/spec/controllers/abuse_reports_controller_spec.rb
@@ -13,6 +13,31 @@ describe AbuseReportsController do
sign_in(reporter)
end
+ describe 'GET new' do
+ context 'when the user has already been deleted' do
+ it 'redirects the reporter to root_path' do
+ user_id = user.id
+ user.destroy
+
+ get :new, { user_id: user_id }
+
+ expect(response).to redirect_to root_path
+ expect(flash[:alert]).to eq('Cannot create the abuse report. The user has been deleted.')
+ end
+ end
+
+ context 'when the user has already been blocked' do
+ it 'redirects the reporter to the user\'s profile' do
+ user.block
+
+ get :new, { user_id: user.id }
+
+ expect(response).to redirect_to user
+ expect(flash[:alert]).to eq('Cannot create the abuse report. This user has been blocked.')
+ end
+ end
+ end
+
describe 'POST create' do
context 'with valid attributes' do
it 'saves the abuse report' do
diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb
index e311b8a63b2..7bd6c0e6117 100644
--- a/spec/controllers/admin/applications_controller_spec.rb
+++ b/spec/controllers/admin/applications_controller_spec.rb
@@ -28,13 +28,16 @@ describe Admin::ApplicationsController do
describe 'POST #create' do
it 'creates the application' do
+ create_params = attributes_for(:application, trusted: true)
+
expect do
- post :create, doorkeeper_application: attributes_for(:application)
+ post :create, doorkeeper_application: create_params
end.to change { Doorkeeper::Application.count }.by(1)
application = Doorkeeper::Application.last
expect(response).to redirect_to(admin_application_path(application))
+ expect(application).to have_attributes(create_params.except(:uid, :owner_type))
end
it 'renders the application form on errors' do
@@ -49,10 +52,12 @@ describe Admin::ApplicationsController do
describe 'PATCH #update' do
it 'updates the application' do
- patch :update, id: application.id, doorkeeper_application: { redirect_uri: 'http://example.com/' }
+ patch :update, id: application.id, doorkeeper_application: { redirect_uri: 'http://example.com/', trusted: true }
+
+ application.reload
expect(response).to redirect_to(admin_application_path(application))
- expect(application.reload.redirect_uri).to eq 'http://example.com/'
+ expect(application).to have_attributes(redirect_uri: 'http://example.com/', trusted: true)
end
it 'renders the application form on errors' do
diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb
new file mode 100644
index 00000000000..6eb9f7867d5
--- /dev/null
+++ b/spec/controllers/admin/dashboard_controller_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Admin::DashboardController do
+ describe '#index' do
+ context 'with pending_delete projects' do
+ render_views
+
+ it 'does not retrieve projects that are pending deletion' do
+ sign_in(create(:admin))
+
+ project = create(:project)
+ pending_delete_project = create(:project, pending_delete: true)
+
+ get :index
+
+ expect(response.body).to match(project.name)
+ expect(response.body).not_to match(pending_delete_project.name)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 3f99e2ff596..1641bddea11 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -30,6 +30,15 @@ describe ApplicationController do
expect(controller).not_to receive(:redirect_to)
controller.send(:check_password_expiration)
end
+
+ it 'does not redirect if the user is over their password expiry but sign-in is disabled' do
+ stub_application_setting(password_authentication_enabled: false)
+ user.password_expires_at = Time.new(2002)
+ allow(controller).to receive(:current_user).and_return(user)
+ expect(controller).not_to receive(:redirect_to)
+
+ controller.send(:check_password_expiration)
+ end
end
describe "#authenticate_user_from_token!" do
@@ -99,6 +108,36 @@ describe ApplicationController do
end
end
+ describe 'response format' do
+ controller(described_class) do
+ def index
+ respond_to do |format|
+ format.json do
+ head :ok
+ end
+ end
+ end
+ end
+
+ context 'when format is handled' do
+ let(:requested_format) { :json }
+
+ it 'returns 200 response' do
+ get :index, private_token: user.private_token, format: requested_format
+
+ expect(response).to have_http_status 200
+ end
+ end
+
+ context 'when format is not handled' do
+ it 'returns 404 response' do
+ get :index, private_token: user.private_token
+
+ expect(response).to have_http_status 404
+ end
+ end
+ end
+
describe '#authenticate_user_from_rss_token' do
describe "authenticating a user from an RSS token" do
controller(described_class) do
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index b40f647644d..58486f33229 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -97,6 +97,21 @@ describe AutocompleteController do
it { expect(body.size).to eq User.count }
end
+ context 'user order' do
+ it 'shows exact matches first' do
+ reported_user = create(:user, username: 'reported_user', name: 'Doug')
+ user = create(:user, username: 'user', name: 'User')
+ user1 = create(:user, username: 'user1', name: 'Ian')
+
+ sign_in(user)
+ get(:users, search: 'user')
+
+ response_usernames = JSON.parse(response.body).map { |user| user['username'] }
+
+ expect(response_usernames.take(3)).to match_array([user.username, reported_user.username, user1.username])
+ end
+ end
+
context 'limited users per page' do
let(:per_page) { 2 }
diff --git a/spec/controllers/dashboard/labels_controller_spec.rb b/spec/controllers/dashboard/labels_controller_spec.rb
new file mode 100644
index 00000000000..2b63933008f
--- /dev/null
+++ b/spec/controllers/dashboard/labels_controller_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Dashboard::LabelsController do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let!(:label) { create(:label, project: project) }
+
+ before do
+ sign_in(user)
+ project.add_reporter(user)
+ end
+
+ describe "#index" do
+ let!(:unrelated_label) { create(:label, project: create(:empty_project, :public)) }
+
+ it 'returns global labels for projects the user has a relationship with' do
+ get :index, format: :json
+
+ expect(json_response).to be_kind_of(Array)
+ expect(json_response.size).to eq(1)
+ expect(json_response[0]["id"]).to be_nil
+ expect(json_response[0]["title"]).to eq(label.title)
+ end
+ end
+end
diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb
index 085f3fd8543..4a48621abe1 100644
--- a/spec/controllers/dashboard/todos_controller_spec.rb
+++ b/spec/controllers/dashboard/todos_controller_spec.rb
@@ -12,6 +12,36 @@ describe Dashboard::TodosController do
end
describe 'GET #index' do
+ context 'project authorization' do
+ it 'renders 404 when user does not have read access on given project' do
+ unauthorized_project = create(:empty_project, :private)
+
+ get :index, project_id: unauthorized_project.id
+
+ expect(response).to have_http_status(404)
+ end
+
+ it 'renders 404 when given project does not exists' do
+ get :index, project_id: 999
+
+ expect(response).to have_http_status(404)
+ end
+
+ it 'renders 200 when filtering for "any project" todos' do
+ get :index, project_id: ''
+
+ expect(response).to have_http_status(200)
+ end
+
+ it 'renders 200 when user has access on given project' do
+ authorized_project = create(:empty_project, :public)
+
+ get :index, project_id: authorized_project.id
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
context 'when using pagination' do
let(:last_page) { user.todos.page.total_pages }
let!(:issues) { create_list(:issue, 2, project: project, assignees: [user]) }
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index f3263bc177d..aad67dd0164 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Groups::MilestonesController do
let(:group) { create(:group) }
- let(:project) { create(:empty_project, group: group) }
- let(:project2) { create(:empty_project, group: group) }
+ let!(:project) { create(:empty_project, group: group) }
+ let!(:project2) { create(:empty_project, group: group) }
let(:user) { create(:user) }
let(:title) { '肯定不是中文的问题' }
let(:milestone) do
@@ -17,28 +17,127 @@ describe Groups::MilestonesController do
end
let(:milestone_path) { group_milestone_path(group, milestone.safe_title, title: milestone.title) }
+ let(:milestone_params) do
+ {
+ title: title,
+ start_date: Date.today,
+ due_date: 1.month.from_now.to_date
+ }
+ end
+
before do
sign_in(user)
group.add_owner(user)
project.team << [user, :master]
end
+ describe '#index' do
+ it 'shows group milestones page' do
+ get :index, group_id: group.to_param
+
+ expect(response).to have_http_status(200)
+ end
+
+ context 'as JSON' do
+ let!(:milestone) { create(:milestone, group: group, title: 'group milestone') }
+ let!(:legacy_milestone1) { create(:milestone, project: project, title: 'legacy') }
+ let!(:legacy_milestone2) { create(:milestone, project: project2, title: 'legacy') }
+
+ it 'lists legacy group milestones and group milestones' do
+ get :index, group_id: group.to_param, format: :json
+
+ milestones = JSON.parse(response.body)
+
+ expect(milestones.count).to eq(2)
+ expect(milestones.first["title"]).to eq("group milestone")
+ expect(milestones.second["title"]).to eq("legacy")
+ expect(response).to have_http_status(200)
+ expect(response.content_type).to eq 'application/json'
+ end
+ end
+ end
+
+ describe '#show' do
+ let(:milestone1) { create(:milestone, project: project, title: 'legacy') }
+ let(:milestone2) { create(:milestone, project: project, title: 'legacy') }
+ let(:group_milestone) { create(:milestone, group: group) }
+
+ context 'when there is a title parameter' do
+ it 'searchs for a legacy group milestone' do
+ expect(GlobalMilestone).to receive(:build)
+ expect(Milestone).not_to receive(:find_by_iid)
+
+ get :show, group_id: group.to_param, id: title, title: milestone1.safe_title
+ end
+ end
+
+ context 'when there is not a title parameter' do
+ it 'searchs for a group milestone' do
+ expect(GlobalMilestone).not_to receive(:build)
+ expect(Milestone).to receive(:find_by_iid)
+
+ get :show, group_id: group.to_param, id: group_milestone.id
+ end
+ end
+ end
+
it_behaves_like 'milestone tabs'
describe "#create" do
it "creates group milestone with Chinese title" do
post :create,
group_id: group.to_param,
- milestone: { project_ids: [project.id, project2.id], title: title }
+ milestone: milestone_params
+
+ milestone = Milestone.find_by_title(title)
+
+ expect(response).to redirect_to(group_milestone_path(group, milestone.iid))
+ expect(milestone.group_id).to eq(group.id)
+ expect(milestone.due_date).to eq(milestone_params[:due_date])
+ expect(milestone.start_date).to eq(milestone_params[:start_date])
+ end
+ end
+
+ describe "#update" do
+ let(:milestone) { create(:milestone, group: group) }
+
+ it "updates group milestone" do
+ milestone_params[:title] = "title changed"
+
+ put :update,
+ id: milestone.iid,
+ group_id: group.to_param,
+ milestone: milestone_params
- expect(response).to redirect_to(group_milestone_path(group, title.to_slug.to_s, title: title))
- expect(Milestone.where(title: title).count).to eq(2)
+ milestone.reload
+ expect(response).to redirect_to(group_milestone_path(group, milestone.iid))
+ expect(milestone.title).to eq("title changed")
end
- it "redirects to new when there are no project ids" do
- post :create, group_id: group.to_param, milestone: { title: title, project_ids: [""] }
- expect(response).to render_template :new
- expect(assigns(:milestone).errors).not_to be_nil
+ context "legacy group milestones" do
+ let!(:milestone1) { create(:milestone, project: project, title: 'legacy milestone', description: "old description") }
+ let!(:milestone2) { create(:milestone, project: project2, title: 'legacy milestone', description: "old description") }
+
+ it "updates only group milestones state" do
+ milestone_params[:title] = "title changed"
+ milestone_params[:description] = "description changed"
+ milestone_params[:state_event] = "close"
+
+ put :update,
+ id: milestone1.title.to_slug.to_s,
+ group_id: group.to_param,
+ milestone: milestone_params,
+ title: milestone1.title
+
+ expect(response).to redirect_to(group_milestone_path(group, milestone1.safe_title, title: milestone1.title))
+
+ [milestone1, milestone2].each do |milestone|
+ milestone.reload
+ expect(milestone.title).to eq("legacy milestone")
+ expect(milestone.description).to eq("old description")
+ expect(milestone.state).to eq("closed")
+ end
+ end
end
end
@@ -141,7 +240,7 @@ describe Groups::MilestonesController do
it 'does not 404' do
post :create,
group_id: group.to_param,
- milestone: { project_ids: [project.id, project2.id], title: title }
+ milestone: { title: title }
expect(response).not_to have_http_status(404)
end
@@ -149,7 +248,7 @@ describe Groups::MilestonesController do
it 'does not redirect to the correct casing' do
post :create,
group_id: group.to_param,
- milestone: { project_ids: [project.id, project2.id], title: title }
+ milestone: { title: title }
expect(response).not_to have_http_status(301)
end
@@ -161,7 +260,7 @@ describe Groups::MilestonesController do
it 'returns not found' do
post :create,
group_id: redirect_route.path,
- milestone: { project_ids: [project.id, project2.id], title: title }
+ milestone: { title: title }
expect(response).to have_http_status(404)
end
diff --git a/spec/controllers/groups/settings/ci_cd_controller_spec.rb b/spec/controllers/groups/settings/ci_cd_controller_spec.rb
new file mode 100644
index 00000000000..2e0efb57c74
--- /dev/null
+++ b/spec/controllers/groups/settings/ci_cd_controller_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Groups::Settings::CiCdController do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
+ before do
+ group.add_master(user)
+ sign_in(user)
+ end
+
+ describe 'GET #show' do
+ it 'renders show with 200 status code' do
+ get :show, group_id: group
+
+ expect(response).to have_http_status(200)
+ expect(response).to render_template(:show)
+ end
+ end
+end
diff --git a/spec/controllers/groups/variables_controller_spec.rb b/spec/controllers/groups/variables_controller_spec.rb
new file mode 100644
index 00000000000..02f2fa46047
--- /dev/null
+++ b/spec/controllers/groups/variables_controller_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+
+describe Groups::VariablesController do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ group.add_master(user)
+ end
+
+ describe 'POST #create' do
+ context 'variable is valid' do
+ it 'shows a success flash message' do
+ post :create, group_id: group, variable: { key: "one", value: "two" }
+
+ expect(flash[:notice]).to include 'Variable was successfully created.'
+ expect(response).to redirect_to(group_settings_ci_cd_path(group))
+ end
+ end
+
+ context 'variable is invalid' do
+ it 'renders show' do
+ post :create, group_id: group, variable: { key: "..one", value: "two" }
+
+ expect(response).to render_template("groups/variables/show")
+ end
+ end
+ end
+
+ describe 'POST #update' do
+ let(:variable) { create(:ci_group_variable) }
+
+ context 'updating a variable with valid characters' do
+ before do
+ group.variables << variable
+ end
+
+ it 'shows a success flash message' do
+ post :update, group_id: group,
+ id: variable.id, variable: { key: variable.key, value: 'two' }
+
+ expect(flash[:notice]).to include 'Variable was successfully updated.'
+ expect(response).to redirect_to(group_variables_path(group))
+ end
+
+ it 'renders the action #show if the variable key is invalid' do
+ post :update, group_id: group,
+ id: variable.id, variable: { key: '?', value: variable.value }
+
+ expect(response).to have_http_status(200)
+ expect(response).to render_template :show
+ end
+ end
+ end
+end
diff --git a/spec/controllers/health_check_controller_spec.rb b/spec/controllers/health_check_controller_spec.rb
index 58c16cc57e6..03da6287774 100644
--- a/spec/controllers/health_check_controller_spec.rb
+++ b/spec/controllers/health_check_controller_spec.rb
@@ -3,52 +3,79 @@ require 'spec_helper'
describe HealthCheckController do
include StubENV
- let(:token) { current_application_settings.health_check_access_token }
let(:json_response) { JSON.parse(response.body) }
let(:xml_response) { Hash.from_xml(response.body)['hash'] }
+ let(:token) { current_application_settings.health_check_access_token }
+ let(:whitelisted_ip) { '127.0.0.1' }
+ let(:not_whitelisted_ip) { '127.0.0.2' }
before do
+ allow(Settings.monitoring).to receive(:ip_whitelist).and_return([whitelisted_ip])
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end
describe 'GET #index' do
- context 'when services are up but NO access token' do
+ context 'when services are up but accessed from outside whitelisted ips' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
+ end
+
it 'returns a not found page' do
get :index
+
expect(response).to be_not_found
end
+
+ context 'when services are accessed with token' do
+ it 'supports passing the token in the header' do
+ request.headers['TOKEN'] = token
+
+ get :index
+
+ expect(response).to be_success
+ expect(response.content_type).to eq 'text/plain'
+ end
+
+ it 'supports passing the token in query params' do
+ get :index, token: token
+
+ expect(response).to be_success
+ expect(response.content_type).to eq 'text/plain'
+ end
+ end
end
- context 'when services are up and an access token is provided' do
- it 'supports passing the token in the header' do
- request.headers['TOKEN'] = token
- get :index
- expect(response).to be_success
- expect(response.content_type).to eq 'text/plain'
+ context 'when services are up and accessed from whitelisted ips' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
end
- it 'supports successful plaintest response' do
- get :index, token: token
+ it 'supports successful plaintext response' do
+ get :index
+
expect(response).to be_success
expect(response.content_type).to eq 'text/plain'
end
it 'supports successful json response' do
- get :index, token: token, format: :json
+ get :index, format: :json
+
expect(response).to be_success
expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be true
end
it 'supports successful xml response' do
- get :index, token: token, format: :xml
+ get :index, format: :xml
+
expect(response).to be_success
expect(response.content_type).to eq 'application/xml'
expect(xml_response['healthy']).to be true
end
it 'supports successful responses for specific checks' do
- get :index, token: token, checks: 'email', format: :json
+ get :index, checks: 'email', format: :json
+
expect(response).to be_success
expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be true
@@ -58,33 +85,29 @@ describe HealthCheckController do
context 'when a service is down but NO access token' do
it 'returns a not found page' do
get :index
+
expect(response).to be_not_found
end
end
- context 'when a service is down and an access token is provided' do
+ context 'when a service is down and an endpoint is accessed from whitelisted ip' do
before do
allow(HealthCheck::Utils).to receive(:process_checks).with(['standard']).and_return('The server is on fire')
allow(HealthCheck::Utils).to receive(:process_checks).with(['email']).and_return('Email is on fire')
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
end
- it 'supports passing the token in the header' do
- request.headers['TOKEN'] = token
+ it 'supports failure plaintext response' do
get :index
- expect(response).to have_http_status(500)
- expect(response.content_type).to eq 'text/plain'
- expect(response.body).to include('The server is on fire')
- end
- it 'supports failure plaintest response' do
- get :index, token: token
expect(response).to have_http_status(500)
expect(response.content_type).to eq 'text/plain'
expect(response.body).to include('The server is on fire')
end
it 'supports failure json response' do
- get :index, token: token, format: :json
+ get :index, format: :json
+
expect(response).to have_http_status(500)
expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be false
@@ -92,7 +115,8 @@ describe HealthCheckController do
end
it 'supports failure xml response' do
- get :index, token: token, format: :xml
+ get :index, format: :xml
+
expect(response).to have_http_status(500)
expect(response.content_type).to eq 'application/xml'
expect(xml_response['healthy']).to be false
@@ -100,7 +124,8 @@ describe HealthCheckController do
end
it 'supports failure responses for specific checks' do
- get :index, token: token, checks: 'email', format: :json
+ get :index, checks: 'email', format: :json
+
expect(response).to have_http_status(500)
expect(response.content_type).to eq 'application/json'
expect(json_response['healthy']).to be false
diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb
index e7c19b47a6a..cc389e554ad 100644
--- a/spec/controllers/health_controller_spec.rb
+++ b/spec/controllers/health_controller_spec.rb
@@ -3,55 +3,120 @@ require 'spec_helper'
describe HealthController do
include StubENV
- let(:token) { current_application_settings.health_check_access_token }
let(:json_response) { JSON.parse(response.body) }
+ let(:token) { current_application_settings.health_check_access_token }
+ let(:whitelisted_ip) { '127.0.0.1' }
+ let(:not_whitelisted_ip) { '127.0.0.2' }
before do
+ allow(Settings.monitoring).to receive(:ip_whitelist).and_return([whitelisted_ip])
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end
describe '#readiness' do
- context 'authorization token provided' do
- before do
- request.headers['TOKEN'] = token
- end
+ shared_context 'endpoint responding with readiness data' do
+ let(:request_params) { {} }
+
+ subject { get :readiness, request_params }
+
+ it 'responds with readiness checks data' do
+ subject
- it 'returns proper response' do
- get :readiness
expect(json_response['db_check']['status']).to eq('ok')
- expect(json_response['redis_check']['status']).to eq('ok')
+ expect(json_response['cache_check']['status']).to eq('ok')
+ expect(json_response['queues_check']['status']).to eq('ok')
+ expect(json_response['shared_state_check']['status']).to eq('ok')
expect(json_response['fs_shards_check']['status']).to eq('ok')
expect(json_response['fs_shards_check']['labels']['shard']).to eq('default')
end
end
- context 'without authorization token' do
- it 'returns proper response' do
+ context 'accessed from whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
+ end
+
+ it_behaves_like 'endpoint responding with readiness data'
+ end
+
+ context 'accessed from not whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
+ end
+
+ it 'responds with resource not found' do
get :readiness
+
expect(response.status).to eq(404)
end
+
+ context 'accessed with valid token' do
+ context 'token passed in request header' do
+ before do
+ request.headers['TOKEN'] = token
+ end
+
+ it_behaves_like 'endpoint responding with readiness data'
+ end
+ end
+
+ context 'token passed as URL param' do
+ it_behaves_like 'endpoint responding with readiness data' do
+ let(:request_params) { { token: token } }
+ end
+ end
end
end
describe '#liveness' do
- context 'authorization token provided' do
- before do
- request.headers['TOKEN'] = token
- end
+ shared_context 'endpoint responding with liveness data' do
+ subject { get :liveness }
+
+ it 'responds with liveness checks data' do
+ subject
- it 'returns proper response' do
- get :liveness
expect(json_response['db_check']['status']).to eq('ok')
- expect(json_response['redis_check']['status']).to eq('ok')
+ expect(json_response['cache_check']['status']).to eq('ok')
+ expect(json_response['queues_check']['status']).to eq('ok')
+ expect(json_response['shared_state_check']['status']).to eq('ok')
expect(json_response['fs_shards_check']['status']).to eq('ok')
end
end
- context 'without authorization token' do
- it 'returns proper response' do
+ context 'accessed from whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
+ end
+
+ it_behaves_like 'endpoint responding with liveness data'
+ end
+
+ context 'accessed from not whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
+ end
+
+ it 'responds with resource not found' do
get :liveness
+
expect(response.status).to eq(404)
end
+
+ context 'accessed with valid token' do
+ context 'token passed in request header' do
+ before do
+ request.headers['TOKEN'] = token
+ end
+
+ it_behaves_like 'endpoint responding with liveness data'
+ end
+
+ context 'token passed as URL param' do
+ it_behaves_like 'endpoint responding with liveness data' do
+ subject { get :liveness, token: token }
+ end
+ end
+ end
end
end
end
diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb
index 044c9f179ed..7b0976e3e67 100644
--- a/spec/controllers/metrics_controller_spec.rb
+++ b/spec/controllers/metrics_controller_spec.rb
@@ -3,28 +3,28 @@ require 'spec_helper'
describe MetricsController do
include StubENV
- let(:token) { current_application_settings.health_check_access_token }
let(:json_response) { JSON.parse(response.body) }
let(:metrics_multiproc_dir) { Dir.mktmpdir }
+ let(:whitelisted_ip) { '127.0.0.1' }
+ let(:whitelisted_ip_range) { '10.0.0.0/24' }
+ let(:ip_in_whitelisted_range) { '10.0.0.1' }
+ let(:not_whitelisted_ip) { '10.0.1.1' }
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- stub_env('prometheus_multiproc_dir', metrics_multiproc_dir)
+ allow(Prometheus::Client.configuration).to receive(:multiprocess_files_dir).and_return(metrics_multiproc_dir)
allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true)
+ allow(Settings.monitoring).to receive(:ip_whitelist).and_return([whitelisted_ip, whitelisted_ip_range])
end
describe '#index' do
- context 'authorization token provided' do
- before do
- request.headers['TOKEN'] = token
- end
-
+ shared_examples_for 'endpoint providing metrics' do
it 'returns DB ping metrics' do
get :index
expect(response.body).to match(/^db_ping_timeout 0$/)
expect(response.body).to match(/^db_ping_success 1$/)
- expect(response.body).to match(/^db_ping_latency [0-9\.]+$/)
+ expect(response.body).to match(/^db_ping_latency_seconds [0-9\.]+$/)
end
it 'returns Redis ping metrics' do
@@ -32,17 +32,41 @@ describe MetricsController do
expect(response.body).to match(/^redis_ping_timeout 0$/)
expect(response.body).to match(/^redis_ping_success 1$/)
- expect(response.body).to match(/^redis_ping_latency [0-9\.]+$/)
+ expect(response.body).to match(/^redis_ping_latency_seconds [0-9\.]+$/)
+ end
+
+ it 'returns Caching ping metrics' do
+ get :index
+
+ expect(response.body).to match(/^redis_cache_ping_timeout 0$/)
+ expect(response.body).to match(/^redis_cache_ping_success 1$/)
+ expect(response.body).to match(/^redis_cache_ping_latency_seconds [0-9\.]+$/)
+ end
+
+ it 'returns Queues ping metrics' do
+ get :index
+
+ expect(response.body).to match(/^redis_queues_ping_timeout 0$/)
+ expect(response.body).to match(/^redis_queues_ping_success 1$/)
+ expect(response.body).to match(/^redis_queues_ping_latency_seconds [0-9\.]+$/)
+ end
+
+ it 'returns SharedState ping metrics' do
+ get :index
+
+ expect(response.body).to match(/^redis_shared_state_ping_timeout 0$/)
+ expect(response.body).to match(/^redis_shared_state_ping_success 1$/)
+ expect(response.body).to match(/^redis_shared_state_ping_latency_seconds [0-9\.]+$/)
end
it 'returns file system check metrics' do
get :index
- expect(response.body).to match(/^filesystem_access_latency{shard="default"} [0-9\.]+$/)
+ expect(response.body).to match(/^filesystem_access_latency_seconds{shard="default"} [0-9\.]+$/)
expect(response.body).to match(/^filesystem_accessible{shard="default"} 1$/)
- expect(response.body).to match(/^filesystem_write_latency{shard="default"} [0-9\.]+$/)
+ expect(response.body).to match(/^filesystem_write_latency_seconds{shard="default"} [0-9\.]+$/)
expect(response.body).to match(/^filesystem_writable{shard="default"} 1$/)
- expect(response.body).to match(/^filesystem_read_latency{shard="default"} [0-9\.]+$/)
+ expect(response.body).to match(/^filesystem_read_latency_seconds{shard="default"} [0-9\.]+$/)
expect(response.body).to match(/^filesystem_readable{shard="default"} 1$/)
end
@@ -59,7 +83,27 @@ describe MetricsController do
end
end
- context 'without authorization token' do
+ context 'accessed from whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(whitelisted_ip)
+ end
+
+ it_behaves_like 'endpoint providing metrics'
+ end
+
+ context 'accessed from ip in whitelisted range' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(ip_in_whitelisted_range)
+ end
+
+ it_behaves_like 'endpoint providing metrics'
+ end
+
+ context 'accessed from not whitelisted ip' do
+ before do
+ allow(Gitlab::RequestContext).to receive(:client_ip).and_return(not_whitelisted_ip)
+ end
+
it 'returns proper response' do
get :index
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
index d321bfcea9d..ac7f73c6e81 100644
--- a/spec/controllers/oauth/authorizations_controller_spec.rb
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -42,8 +42,8 @@ describe Oauth::AuthorizationsController do
end
it 'deletes session.user_return_to and redirects when skip authorization' do
+ doorkeeper.update(trusted: true)
request.session['user_return_to'] = 'http://example.com'
- allow(controller).to receive(:skip_authorization?).and_return(true)
get :new, params
diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb
new file mode 100644
index 00000000000..2955d01fad0
--- /dev/null
+++ b/spec/controllers/passwords_controller_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe PasswordsController do
+ describe '#check_password_authentication_available' do
+ before do
+ @request.env["devise.mapping"] = Devise.mappings[:user]
+ end
+
+ context 'when password authentication is disabled' do
+ it 'prevents a password reset' do
+ stub_application_setting(password_authentication_enabled: false)
+
+ post :create
+
+ expect(flash[:alert]).to eq 'Password authentication is unavailable.'
+ end
+ end
+
+ context 'when reset email belongs to an ldap user' do
+ let(:user) { create(:omniauth_user, provider: 'ldapmain', email: 'ldapuser@gitlab.com') }
+
+ it 'prevents a password reset' do
+ post :create, user: { email: user.email }
+
+ expect(flash[:alert]).to eq 'Password authentication is unavailable.'
+ end
+ end
+ end
+end
diff --git a/spec/controllers/profiles/accounts_controller_spec.rb b/spec/controllers/profiles/accounts_controller_spec.rb
index 2f9d18e3a0e..d387aba227b 100644
--- a/spec/controllers/profiles/accounts_controller_spec.rb
+++ b/spec/controllers/profiles/accounts_controller_spec.rb
@@ -29,7 +29,7 @@ describe Profiles::AccountsController do
end
end
- [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0].each do |provider|
+ [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0, :authentiq].each do |provider|
describe "#{provider} provider" do
let(:user) { create(:omniauth_user, provider: provider.to_s) }
diff --git a/spec/controllers/profiles/preferences_controller_spec.rb b/spec/controllers/profiles/preferences_controller_spec.rb
index 7b3aa0491c7..a5f544b4f92 100644
--- a/spec/controllers/profiles/preferences_controller_spec.rb
+++ b/spec/controllers/profiles/preferences_controller_spec.rb
@@ -43,7 +43,8 @@ describe Profiles::PreferencesController do
dashboard: 'stars'
}.with_indifferent_access
- expect(user).to receive(:update_attributes).with(prefs)
+ expect(user).to receive(:assign_attributes).with(prefs)
+ expect(user).to receive(:save)
go params: prefs
end
@@ -51,7 +52,7 @@ describe Profiles::PreferencesController do
context 'on failed update' do
it 'sets the flash' do
- expect(user).to receive(:update_attributes).and_return(false)
+ expect(user).to receive(:save).and_return(false)
go
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb
index 428bc45b842..d2c613a2423 100644
--- a/spec/controllers/projects/artifacts_controller_spec.rb
+++ b/spec/controllers/projects/artifacts_controller_spec.rb
@@ -134,10 +134,7 @@ describe Projects::ArtifactsController do
context 'found the job and redirect' do
shared_examples 'redirect to the job' do
it 'redirects' do
- path = browse_namespace_project_job_artifacts_path(
- project.namespace,
- project,
- job)
+ path = browse_project_job_artifacts_path(project, job)
expect(response).to redirect_to(path)
end
@@ -174,11 +171,7 @@ describe Projects::ArtifactsController do
end
it 'redirects' do
- path = file_namespace_project_job_artifacts_path(
- project.namespace,
- project,
- job,
- 'README.md')
+ path = file_project_job_artifacts_path(project, job, 'README.md')
expect(response).to redirect_to(path)
end
diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb
new file mode 100644
index 00000000000..d68200164e4
--- /dev/null
+++ b/spec/controllers/projects/badges_controller_spec.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+describe Projects::BadgesController do
+ let(:project) { pipeline.project }
+ let!(:pipeline) { create(:ci_empty_pipeline) }
+ let(:user) { create(:user) }
+
+ before do
+ project.add_master(user)
+ sign_in(user)
+ end
+
+ it 'requests the pipeline badge successfully' do
+ get_badge(:pipeline)
+
+ expect(response).to have_http_status(:ok)
+ end
+
+ it 'requests the coverage badge successfully' do
+ get_badge(:coverage)
+
+ expect(response).to have_http_status(:ok)
+ end
+
+ def get_badge(badge)
+ get badge, namespace_id: project.namespace.to_param, project_id: project, ref: pipeline.ref, format: :svg
+ end
+end
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index c20cf6a4291..02bbc48dc59 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -117,7 +117,7 @@ describe Projects::BlobController do
end
it 'redirects to blob show' do
- expect(response).to redirect_to(namespace_project_blob_path(project.namespace, project, 'master/CHANGELOG'))
+ expect(response).to redirect_to(project_blob_path(project, 'master/CHANGELOG'))
end
end
@@ -164,7 +164,7 @@ describe Projects::BlobController do
end
def blob_after_edit_path
- namespace_project_blob_path(project.namespace, project, 'master/CHANGELOG')
+ project_blob_path(project, 'master/CHANGELOG')
end
before do
@@ -186,7 +186,7 @@ describe Projects::BlobController do
it 'redirects to MR diff' do
put :update, mr_params
- after_edit_path = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ after_edit_path = diffs_project_merge_request_path(project, merge_request)
file_anchor = "##{Digest::SHA1.hexdigest('CHANGELOG')}"
expect(response).to redirect_to(after_edit_path + file_anchor)
end
@@ -223,7 +223,7 @@ describe Projects::BlobController do
it 'redirects to blob' do
put :update, default_params
- expect(response).to redirect_to(namespace_project_blob_path(forked_project.namespace, forked_project, 'master/CHANGELOG'))
+ expect(response).to redirect_to(project_blob_path(forked_project, 'master/CHANGELOG'))
end
end
@@ -235,8 +235,7 @@ describe Projects::BlobController do
put :update, default_params
expect(response).to redirect_to(
- new_namespace_project_merge_request_path(
- forked_project.namespace,
+ project_new_merge_request_path(
forked_project,
merge_request: {
source_project_id: forked_project.id,
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index 14426b09c73..9cd4e9dbf84 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -110,7 +110,7 @@ describe Projects::BranchesController do
branch_name: branch,
issue_iid: issue.iid
- expect(response).to redirect_to namespace_project_tree_path(project.namespace, project, branch)
+ expect(response).to redirect_to project_tree_path(project, branch)
end
it 'redirects to autodeploy setup page' do
@@ -127,7 +127,7 @@ describe Projects::BranchesController do
branch_name: branch,
issue_iid: issue.iid
- expect(response.location).to include(namespace_project_new_blob_path(project.namespace, project, branch))
+ expect(response.location).to include(project_new_blob_path(project, branch))
expect(response).to have_http_status(302)
end
end
@@ -303,7 +303,7 @@ describe Projects::BranchesController do
it 'redirects to branches path' do
expect(response)
- .to redirect_to(namespace_project_branches_path(project.namespace, project))
+ .to redirect_to(project_branches_path(project))
end
end
end
@@ -323,7 +323,7 @@ describe Projects::BranchesController do
it 'redirects to branches' do
destroy_all_merged
- expect(response).to redirect_to namespace_project_branches_path(project.namespace, project)
+ expect(response).to redirect_to project_branches_path(project)
end
it 'starts worker to delete merged branches' do
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index e10da40eaab..df53863482d 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -169,7 +169,7 @@ describe Projects::CommitController do
start_branch: 'master',
id: commit.id)
- expect(response).to redirect_to namespace_project_commits_path(project.namespace, project, 'master')
+ expect(response).to redirect_to project_commits_path(project, 'master')
expect(flash[:notice]).to eq('The commit has been successfully reverted.')
end
end
@@ -191,7 +191,7 @@ describe Projects::CommitController do
start_branch: 'master',
id: commit.id)
- expect(response).to redirect_to namespace_project_commit_path(project.namespace, project, commit.id)
+ expect(response).to redirect_to project_commit_path(project, commit.id)
expect(flash[:alert]).to match('Sorry, we cannot revert this commit automatically.')
end
end
@@ -218,7 +218,7 @@ describe Projects::CommitController do
start_branch: 'master',
id: master_pickable_commit.id)
- expect(response).to redirect_to namespace_project_commits_path(project.namespace, project, 'master')
+ expect(response).to redirect_to project_commits_path(project, 'master')
expect(flash[:notice]).to eq('The commit has been successfully cherry-picked.')
end
end
@@ -240,7 +240,7 @@ describe Projects::CommitController do
start_branch: 'master',
id: master_pickable_commit.id)
- expect(response).to redirect_to namespace_project_commit_path(project.namespace, project, master_pickable_commit.id)
+ expect(response).to redirect_to project_commit_path(project, master_pickable_commit.id)
expect(flash[:alert]).to match('Sorry, we cannot cherry-pick this commit automatically.')
end
end
@@ -343,7 +343,8 @@ describe Projects::CommitController do
get_pipelines(id: commit.id, format: :json)
expect(response).to be_ok
- expect(JSON.parse(response.body)).not_to be_empty
+ expect(JSON.parse(response.body)['pipelines']).not_to be_empty
+ expect(JSON.parse(response.body)['count']['all']).to eq 1
end
end
end
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 8f4694c9854..b4f9fd9b7a2 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -72,7 +72,7 @@ describe Projects::CompareController do
from: '',
to: 'master')
- expect(response).to redirect_to(namespace_project_compare_index_path(project.namespace, project, to: 'master'))
+ expect(response).to redirect_to(project_compare_index_path(project, to: 'master'))
end
it 'redirects back to index when params[:to] is empty and preserves params[:from]' do
@@ -82,7 +82,7 @@ describe Projects::CompareController do
from: 'master',
to: '')
- expect(response).to redirect_to(namespace_project_compare_index_path(project.namespace, project, from: 'master'))
+ expect(response).to redirect_to(project_compare_index_path(project, from: 'master'))
end
it 'redirects back to index when params[:from] and params[:to] are empty' do
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb
index 4c69443314d..0dbfcf97f6f 100644
--- a/spec/controllers/projects/deployments_controller_spec.rb
+++ b/spec/controllers/projects/deployments_controller_spec.rb
@@ -42,6 +42,7 @@ describe Projects::DeploymentsController do
before do
allow(controller).to receive(:deployment).and_return(deployment)
end
+
context 'when metrics are disabled' do
before do
allow(deployment).to receive(:has_metrics?).and_return false
@@ -108,6 +109,69 @@ describe Projects::DeploymentsController do
end
end
+ describe 'GET #additional_metrics' do
+ let(:deployment) { create(:deployment, project: project, environment: environment) }
+
+ before do
+ allow(controller).to receive(:deployment).and_return(deployment)
+ end
+
+ context 'when metrics are disabled' do
+ before do
+ allow(deployment).to receive(:has_metrics?).and_return false
+ end
+
+ it 'responds with not found' do
+ get :metrics, deployment_params(id: deployment.id)
+
+ expect(response).to be_not_found
+ end
+ end
+
+ context 'when metrics are enabled' do
+ let(:prometheus_service) { double('prometheus_service') }
+
+ before do
+ allow(deployment.project).to receive(:prometheus_service).and_return(prometheus_service)
+ end
+
+ context 'when environment has no metrics' do
+ before do
+ expect(deployment).to receive(:additional_metrics).and_return({})
+ end
+
+ it 'returns a empty response 204 response' do
+ get :additional_metrics, deployment_params(id: deployment.id, format: :json)
+ expect(response).to have_http_status(204)
+ expect(response.body).to eq('')
+ end
+ end
+
+ context 'when environment has some metrics' do
+ let(:empty_metrics) do
+ {
+ success: true,
+ metrics: {},
+ last_update: 42
+ }
+ end
+
+ before do
+ expect(deployment).to receive(:additional_metrics).and_return(empty_metrics)
+ end
+
+ it 'returns a metrics JSON document' do
+ get :additional_metrics, deployment_params(id: deployment.id, format: :json)
+
+ expect(response).to be_ok
+ expect(json_response['success']).to be(true)
+ expect(json_response['metrics']).to eq({})
+ expect(json_response['last_update']).to eq(42)
+ end
+ end
+ end
+ end
+
def deployment_params(opts = {})
opts.reverse_merge(namespace_id: project.namespace,
project_id: project,
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 9ec3c53174e..f88f50c3cc6 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -58,11 +58,9 @@ describe Projects::EnvironmentsController do
expect(json_response['stopped_count']).to eq 1
end
- it 'does not set the polling interval header' do
- # TODO, this is a temporary fix, see follow up issue:
- # https://gitlab.com/gitlab-org/gitlab-ee/issues/2677
+ it 'sets the polling interval header' do
expect(response).to have_http_status(:ok)
- expect(response.headers['Poll-Interval']).to be_nil
+ expect(response.headers['Poll-Interval']).to eq("3000")
end
end
@@ -184,7 +182,7 @@ describe Projects::EnvironmentsController do
expect(response).to have_http_status(200)
expect(json_response).to eq(
{ 'redirect_url' =>
- namespace_project_job_url(project.namespace, project, action) })
+ project_job_url(project, action) })
end
end
@@ -198,7 +196,7 @@ describe Projects::EnvironmentsController do
expect(response).to have_http_status(200)
expect(json_response).to eq(
{ 'redirect_url' =>
- namespace_project_environment_url(project.namespace, project, environment) })
+ project_environment_url(project, environment) })
end
end
end
@@ -318,6 +316,48 @@ describe Projects::EnvironmentsController do
end
end
+ describe 'GET #additional_metrics' do
+ before do
+ allow(controller).to receive(:environment).and_return(environment)
+ end
+
+ context 'when environment has no metrics' do
+ before do
+ expect(environment).to receive(:additional_metrics).and_return(nil)
+ end
+
+ context 'when requesting metrics as JSON' do
+ it 'returns a metrics JSON document' do
+ get :additional_metrics, environment_params(format: :json)
+
+ expect(response).to have_http_status(204)
+ expect(json_response).to eq({})
+ end
+ end
+ end
+
+ context 'when environment has some metrics' do
+ before do
+ expect(environment)
+ .to receive(:additional_metrics)
+ .and_return({
+ success: true,
+ data: {},
+ last_update: 42
+ })
+ end
+
+ it 'returns a metrics JSON document' do
+ get :additional_metrics, environment_params(format: :json)
+
+ expect(response).to be_ok
+ expect(json_response['success']).to be(true)
+ expect(json_response['data']).to eq({})
+ expect(json_response['last_update']).to eq(42)
+ end
+ end
+ end
+
def environment_params(opts = {})
opts.reverse_merge(namespace_id: project.namespace,
project_id: project,
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index b5435357f53..019a50882ab 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -34,7 +34,7 @@ describe Projects::GroupLinksController do
it 'redirects to project group links page' do
expect(response).to redirect_to(
- namespace_project_settings_members_path(project.namespace, project)
+ project_project_members_path(project)
)
end
end
@@ -65,7 +65,7 @@ describe Projects::GroupLinksController do
it 'redirects to project group links page' do
expect(response).to redirect_to(
- namespace_project_settings_members_path(project.namespace, project)
+ project_project_members_path(project)
)
end
end
@@ -79,7 +79,7 @@ describe Projects::GroupLinksController do
it 'redirects to project group links page' do
expect(response).to redirect_to(
- namespace_project_settings_members_path(project.namespace, project)
+ project_project_members_path(project)
)
expect(flash[:alert]).to eq('Please select a group.')
end
diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb
new file mode 100644
index 00000000000..b93ab220f4d
--- /dev/null
+++ b/spec/controllers/projects/hooks_controller_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Projects::HooksController do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ end
+
+ describe '#index' do
+ it 'redirects to settings/integrations page' do
+ get(:index, namespace_id: project.namespace, project_id: project)
+
+ expect(response).to redirect_to(
+ project_settings_integrations_path(project)
+ )
+ end
+ end
+end
diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb
index 6724b474179..9be61342616 100644
--- a/spec/controllers/projects/imports_controller_spec.rb
+++ b/spec/controllers/projects/imports_controller_spec.rb
@@ -59,7 +59,7 @@ describe Projects::ImportsController do
it 'redirects to new_namespace_project_import_path' do
get :show, namespace_id: project.namespace.to_param, project_id: project
- expect(response).to redirect_to new_namespace_project_import_path(project.namespace, project)
+ expect(response).to redirect_to new_project_import_path(project)
end
end
@@ -75,7 +75,7 @@ describe Projects::ImportsController do
get :show, namespace_id: project.namespace.to_param, project_id: project
expect(flash[:notice]).to eq 'The project was successfully forked.'
- expect(response).to redirect_to namespace_project_path(project.namespace, project)
+ expect(response).to redirect_to project_path(project)
end
end
@@ -84,14 +84,14 @@ describe Projects::ImportsController do
get :show, namespace_id: project.namespace.to_param, project_id: project
expect(flash[:notice]).to eq 'The project was successfully imported.'
- expect(response).to redirect_to namespace_project_path(project.namespace, project)
+ expect(response).to redirect_to project_path(project)
end
end
context 'when continue params is present' do
let(:params) do
{
- to: namespace_project_path(project.namespace, project),
+ to: project_path(project),
notice: 'Finished'
}
end
@@ -120,7 +120,7 @@ describe Projects::ImportsController do
it 'redirects to namespace_project_path' do
get :show, namespace_id: project.namespace.to_param, project_id: project
- expect(response).to redirect_to namespace_project_path(project.namespace, project)
+ expect(response).to redirect_to project_path(project)
end
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 9f98427a86b..2c57f3bcf8d 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -7,14 +7,30 @@ describe Projects::IssuesController do
describe "GET #index" do
context 'external issue tracker' do
- it 'redirects to the external issue tracker' do
- external = double(project_path: 'https://example.com/project')
- allow(project).to receive(:external_issue_tracker).and_return(external)
- controller.instance_variable_set(:@project, project)
+ before do
+ sign_in(user)
+ project.add_developer(user)
+ create(:jira_service, project: project)
+ end
- get :index, namespace_id: project.namespace, project_id: project
+ context 'when GitLab issues disabled' do
+ it 'returns 404 status' do
+ project.issues_enabled = false
+ project.save!
+
+ get :index, namespace_id: project.namespace, project_id: project
- expect(response).to redirect_to('https://example.com/project')
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when GitLab issues enabled' do
+ it 'renders the "index" template' do
+ get :index, namespace_id: project.namespace, project_id: project
+
+ expect(response).to have_http_status(200)
+ expect(response).to render_template(:index)
+ end
end
end
@@ -35,20 +51,12 @@ describe Projects::IssuesController do
it "returns 301 if request path doesn't match project path" do
get :index, namespace_id: project.namespace, project_id: project.path.upcase
- expect(response).to redirect_to(namespace_project_issues_path(project.namespace, project))
+ expect(response).to redirect_to(project_issues_path(project))
end
it "returns 404 when issues are disabled" do
project.issues_enabled = false
- project.save
-
- get :index, namespace_id: project.namespace, project_id: project
- expect(response).to have_http_status(404)
- end
-
- it "returns 404 when external issue tracker is enabled" do
- controller.instance_variable_set(:@project, project)
- allow(project).to receive(:default_issues_tracker?).and_return(false)
+ project.save!
get :index, namespace_id: project.namespace, project_id: project
expect(response).to have_http_status(404)
@@ -139,19 +147,36 @@ describe Projects::IssuesController do
end
context 'external issue tracker' do
+ let!(:service) do
+ create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker', new_issue_url: 'http://test.com')
+ end
+
before do
sign_in(user)
project.team << [user, :developer]
- end
- it 'redirects to the external issue tracker' do
- external = double(new_issue_path: 'https://example.com/issues/new')
+ external = double
allow(project).to receive(:external_issue_tracker).and_return(external)
- controller.instance_variable_set(:@project, project)
+ end
- get :new, namespace_id: project.namespace, project_id: project
+ context 'when GitLab issues disabled' do
+ it 'returns 404 status' do
+ project.issues_enabled = false
+ project.save!
+
+ get :new, namespace_id: project.namespace, project_id: project
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when GitLab issues enabled' do
+ it 'renders the "new" template' do
+ get :new, namespace_id: project.namespace, project_id: project
- expect(response).to redirect_to('https://example.com/issues/new')
+ expect(response).to have_http_status(200)
+ expect(response).to render_template(:new)
+ end
end
end
end
@@ -329,7 +354,7 @@ describe Projects::IssuesController do
update_verified_issue
expect(response)
- .to redirect_to(namespace_project_issue_path(project.namespace, project, issue))
+ .to redirect_to(project_issue_path(project, issue))
end
it 'accepts an issue after recaptcha is verified' do
@@ -512,6 +537,36 @@ describe Projects::IssuesController do
end
end
+ describe 'GET #realtime_changes' do
+ it_behaves_like 'restricted action', success: 200
+
+ def go(id:)
+ get :realtime_changes,
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: id
+ end
+
+ context 'when an issue was edited by a deleted user' do
+ let(:deleted_user) { create(:user) }
+
+ before do
+ project.team << [user, :developer]
+
+ issue.update!(last_edited_by: deleted_user, last_edited_at: Time.now)
+
+ deleted_user.destroy
+ sign_in(user)
+ end
+
+ it 'returns 200' do
+ go(id: issue.iid)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+ end
+
describe 'GET #edit' do
it_behaves_like 'restricted action', success: 200
@@ -772,7 +827,7 @@ describe Projects::IssuesController do
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
expect(response).to have_http_status(302)
- expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./).now
+ expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./)
end
it 'delegates the update of the todos count cache to TodoService' do
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 472e5fc51a0..5a295ae47a6 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -7,6 +7,10 @@ describe Projects::JobsController do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:user) { create(:user) }
+ before do
+ stub_not_protect_default_branch
+ end
+
describe 'GET index' do
context 'when scope is pending' do
before do
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index bf1776eb320..f19ad4c2c81 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -178,7 +178,7 @@ describe Projects::LabelsController do
it 'redirects to the correct casing' do
get :index, namespace_id: project.namespace, project_id: project.to_param.upcase
- expect(response).to redirect_to(namespace_project_labels_path(project.namespace, project))
+ expect(response).to redirect_to(project_labels_path(project))
expect(controller).not_to set_flash[:notice]
end
end
@@ -191,7 +191,7 @@ describe Projects::LabelsController do
it 'redirects to the canonical path' do
get :index, namespace_id: project.namespace, project_id: project.to_param + 'old'
- expect(response).to redirect_to(namespace_project_labels_path(project.namespace, project))
+ expect(response).to redirect_to(project_labels_path(project))
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, project))
end
end
diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb
index 422a8b6fac0..12e413db902 100644
--- a/spec/controllers/projects/mattermosts_controller_spec.rb
+++ b/spec/controllers/projects/mattermosts_controller_spec.rb
@@ -38,7 +38,7 @@ describe Projects::MattermostsController do
it 'shows the error' do
allow_any_instance_of(MattermostSlashCommandsService).to receive(:configure).and_return([false, "error message"])
- expect(subject).to redirect_to(new_namespace_project_mattermost_url(project.namespace, project))
+ expect(subject).to redirect_to(new_project_mattermost_url(project))
end
end
@@ -51,7 +51,7 @@ describe Projects::MattermostsController do
subject
service = project.services.last
- expect(subject).to redirect_to(edit_namespace_project_service_url(project.namespace, project, service))
+ expect(subject).to redirect_to(edit_project_service_url(project, service))
end
end
end
diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
new file mode 100644
index 00000000000..9278ac8edd8
--- /dev/null
+++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
@@ -0,0 +1,307 @@
+require 'spec_helper'
+
+describe Projects::MergeRequests::ConflictsController do
+ let(:project) { create(:project) }
+ let(:user) { project.owner }
+ let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
+ let(:merge_request_with_conflicts) do
+ create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start', source_project: project) do |mr|
+ mr.mark_as_unmergeable
+ end
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET show' do
+ context 'when the conflicts cannot be resolved in the UI' do
+ before do
+ allow_any_instance_of(Gitlab::Conflict::Parser)
+ .to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
+
+ get :show,
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid,
+ format: 'json'
+ end
+
+ it 'returns a 200 status code' do
+ expect(response).to have_http_status(:ok)
+ end
+
+ it 'returns JSON with a message' do
+ expect(json_response.keys).to contain_exactly('message', 'type')
+ end
+ end
+
+ context 'with valid conflicts' do
+ before do
+ get :show,
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid,
+ format: 'json'
+ end
+
+ it 'matches the schema' do
+ expect(response).to match_response_schema('conflicts')
+ end
+
+ it 'includes meta info about the MR' do
+ expect(json_response['commit_message']).to include('Merge branch')
+ expect(json_response['commit_sha']).to match(/\h{40}/)
+ expect(json_response['source_branch']).to eq(merge_request_with_conflicts.source_branch)
+ expect(json_response['target_branch']).to eq(merge_request_with_conflicts.target_branch)
+ end
+
+ it 'includes each file that has conflicts' do
+ filenames = json_response['files'].map { |file| file['new_path'] }
+
+ expect(filenames).to contain_exactly('files/ruby/popen.rb', 'files/ruby/regex.rb')
+ end
+
+ it 'splits files into sections with lines' do
+ json_response['files'].each do |file|
+ file['sections'].each do |section|
+ expect(section).to include('conflict', 'lines')
+
+ section['lines'].each do |line|
+ if section['conflict']
+ expect(line['type']).to be_in(%w(old new))
+ expect(line.values_at('old_line', 'new_line')).to contain_exactly(nil, a_kind_of(Integer))
+ else
+ if line['type'].nil?
+ expect(line['old_line']).not_to eq(nil)
+ expect(line['new_line']).not_to eq(nil)
+ else
+ expect(line['type']).to eq('match')
+ expect(line['old_line']).to eq(nil)
+ expect(line['new_line']).to eq(nil)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ it 'has unique section IDs across files' do
+ section_ids = json_response['files'].flat_map do |file|
+ file['sections'].map { |section| section['id'] }.compact
+ end
+
+ expect(section_ids.uniq).to eq(section_ids)
+ end
+ end
+ end
+
+ describe 'GET conflict_for_path' do
+ def conflict_for_path(path)
+ get :conflict_for_path,
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid,
+ old_path: path,
+ new_path: path,
+ format: 'json'
+ end
+
+ context 'when the conflicts cannot be resolved in the UI' do
+ before do
+ allow_any_instance_of(Gitlab::Conflict::Parser)
+ .to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
+
+ conflict_for_path('files/ruby/regex.rb')
+ end
+
+ it 'returns a 404 status code' do
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context 'when the file does not exist cannot be resolved in the UI' do
+ before do
+ conflict_for_path('files/ruby/regexp.rb')
+ end
+
+ it 'returns a 404 status code' do
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context 'with an existing file' do
+ let(:path) { 'files/ruby/regex.rb' }
+
+ before do
+ conflict_for_path(path)
+ end
+
+ it 'returns a 200 status code' do
+ expect(response).to have_http_status(:ok)
+ end
+
+ it 'returns the file in JSON format' do
+ content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
+ .file_for_path(path, path)
+ .content
+
+ expect(json_response).to include('old_path' => path,
+ 'new_path' => path,
+ 'blob_icon' => 'file-text-o',
+ 'blob_path' => a_string_ending_with(path),
+ 'blob_ace_mode' => 'ruby',
+ 'content' => content)
+ end
+ end
+ end
+
+ context 'POST resolve_conflicts' do
+ let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
+
+ def resolve_conflicts(files)
+ post :resolve_conflicts,
+ namespace_id: merge_request_with_conflicts.project.namespace.to_param,
+ project_id: merge_request_with_conflicts.project,
+ id: merge_request_with_conflicts.iid,
+ format: 'json',
+ files: files,
+ commit_message: 'Commit message'
+ end
+
+ context 'with valid params' do
+ before do
+ resolved_files = [
+ {
+ 'new_path' => 'files/ruby/popen.rb',
+ 'old_path' => 'files/ruby/popen.rb',
+ 'sections' => {
+ '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
+ }
+ }, {
+ 'new_path' => 'files/ruby/regex.rb',
+ 'old_path' => 'files/ruby/regex.rb',
+ 'sections' => {
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
+ }
+ }
+ ]
+
+ resolve_conflicts(resolved_files)
+ end
+
+ it 'creates a new commit on the branch' do
+ expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
+ expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
+ end
+
+ it 'returns an OK response' do
+ expect(response).to have_http_status(:ok)
+ end
+ end
+
+ context 'when sections are missing' do
+ before do
+ resolved_files = [
+ {
+ 'new_path' => 'files/ruby/popen.rb',
+ 'old_path' => 'files/ruby/popen.rb',
+ 'sections' => {
+ '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
+ }
+ }, {
+ 'new_path' => 'files/ruby/regex.rb',
+ 'old_path' => 'files/ruby/regex.rb',
+ 'sections' => {
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head'
+ }
+ }
+ ]
+
+ resolve_conflicts(resolved_files)
+ end
+
+ it 'returns a 400 error' do
+ expect(response).to have_http_status(:bad_request)
+ end
+
+ it 'has a message with the name of the first missing section' do
+ expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
+ end
+
+ it 'does not create a new commit' do
+ expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
+ end
+ end
+
+ context 'when files are missing' do
+ before do
+ resolved_files = [
+ {
+ 'new_path' => 'files/ruby/regex.rb',
+ 'old_path' => 'files/ruby/regex.rb',
+ 'sections' => {
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
+ }
+ }
+ ]
+
+ resolve_conflicts(resolved_files)
+ end
+
+ it 'returns a 400 error' do
+ expect(response).to have_http_status(:bad_request)
+ end
+
+ it 'has a message with the name of the missing file' do
+ expect(json_response['message']).to include('files/ruby/popen.rb')
+ end
+
+ it 'does not create a new commit' do
+ expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
+ end
+ end
+
+ context 'when a file has identical content to the conflict' do
+ before do
+ content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
+ .file_for_path('files/ruby/popen.rb', 'files/ruby/popen.rb')
+ .content
+
+ resolved_files = [
+ {
+ 'new_path' => 'files/ruby/popen.rb',
+ 'old_path' => 'files/ruby/popen.rb',
+ 'content' => content
+ }, {
+ 'new_path' => 'files/ruby/regex.rb',
+ 'old_path' => 'files/ruby/regex.rb',
+ 'sections' => {
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
+ }
+ }
+ ]
+
+ resolve_conflicts(resolved_files)
+ end
+
+ it 'returns a 400 error' do
+ expect(response).to have_http_status(:bad_request)
+ end
+
+ it 'has a message with the path of the problem file' do
+ expect(json_response['message']).to include('files/ruby/popen.rb')
+ end
+
+ it 'does not create a new commit' do
+ expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
new file mode 100644
index 00000000000..f9d8f0f5fcf
--- /dev/null
+++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb
@@ -0,0 +1,120 @@
+require 'spec_helper'
+
+describe Projects::MergeRequests::CreationsController do
+ let(:project) { create(:project) }
+ let(:user) { project.owner }
+ let(:fork_project) { create(:forked_project_with_submodules) }
+
+ before do
+ fork_project.team << [user, :master]
+
+ sign_in(user)
+ end
+
+ describe 'GET new' do
+ context 'merge request that removes a submodule' do
+ render_views
+
+ it 'renders new merge request widget template' do
+ get :new,
+ namespace_id: fork_project.namespace.to_param,
+ project_id: fork_project,
+ merge_request: {
+ source_branch: 'remove-submodule',
+ target_branch: 'master'
+ }
+
+ expect(response).to be_success
+ end
+ end
+ end
+
+ describe 'GET pipelines' do
+ before do
+ create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id,
+ ref: 'remove-submodule',
+ project: fork_project)
+ end
+
+ it 'renders JSON including serialized pipelines' do
+ get :pipelines,
+ namespace_id: fork_project.namespace.to_param,
+ project_id: fork_project,
+ merge_request: {
+ source_branch: 'remove-submodule',
+ target_branch: 'master'
+ },
+ format: :json
+
+ expect(response).to be_ok
+ expect(json_response).to have_key 'pipelines'
+ expect(json_response['pipelines']).not_to be_empty
+ end
+ end
+
+ describe 'GET diff_for_path' do
+ def diff_for_path(extra_params = {})
+ params = {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ format: 'json'
+ }
+
+ get :diff_for_path, params.merge(extra_params)
+ end
+
+ let(:existing_path) { 'files/ruby/feature.rb' }
+
+ context 'when both branches are in the same project' do
+ it 'disables diff notes' do
+ diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
+
+ expect(assigns(:diff_notes_disabled)).to be_truthy
+ end
+
+ it 'only renders the diffs for the path given' do
+ expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
+ expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
+ meth.call(diffs)
+ end
+
+ diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
+ end
+ end
+
+ context 'when the source branch is in a different project to the target' do
+ let(:other_project) { create(:project) }
+
+ before do
+ other_project.team << [user, :master]
+ end
+
+ context 'when the path exists in the diff' do
+ it 'disables diff notes' do
+ diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
+
+ expect(assigns(:diff_notes_disabled)).to be_truthy
+ end
+
+ it 'only renders the diffs for the path given' do
+ expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
+ expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
+ meth.call(diffs)
+ end
+
+ diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
+ end
+ end
+
+ context 'when the path does not exist in the diff' do
+ before do
+ diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
+ end
+
+ it 'returns a 404' do
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
new file mode 100644
index 00000000000..53fe2bdb189
--- /dev/null
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -0,0 +1,160 @@
+require 'spec_helper'
+
+describe Projects::MergeRequests::DiffsController do
+ let(:project) { create(:project) }
+ let(:user) { project.owner }
+ let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET show' do
+ def go(extra_params = {})
+ params = {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid,
+ format: 'json'
+ }
+
+ get :show, params.merge(extra_params)
+ end
+
+ context 'with default params' do
+ context 'for the same project' do
+ before do
+ go
+ end
+
+ it 'renders the diffs template to a string' do
+ expect(response).to render_template('projects/merge_requests/diffs/_diffs')
+ expect(json_response).to have_key('html')
+ end
+ end
+
+ context 'with forked projects with submodules' do
+ render_views
+
+ let(:project) { create(:project) }
+ let(:fork_project) { create(:forked_project_with_submodules) }
+ let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
+
+ before do
+ fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
+ fork_project.save
+ merge_request.reload
+ go
+ end
+
+ it 'renders' do
+ expect(response).to be_success
+ expect(response.body).to have_content('Subproject commit')
+ end
+ end
+ end
+
+ context 'with ignore_whitespace_change' do
+ before do
+ go(w: 1)
+ end
+
+ it 'renders the diffs template to a string' do
+ expect(response).to render_template('projects/merge_requests/diffs/_diffs')
+ expect(json_response).to have_key('html')
+ end
+ end
+
+ context 'with view' do
+ before do
+ go(view: 'parallel')
+ end
+
+ it 'saves the preferred diff view in a cookie' do
+ expect(response.cookies['diff_view']).to eq('parallel')
+ end
+ end
+ end
+
+ describe 'GET diff_for_path' do
+ def diff_for_path(extra_params = {})
+ params = {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid,
+ format: 'json'
+ }
+
+ get :diff_for_path, params.merge(extra_params)
+ end
+
+ let(:existing_path) { 'files/ruby/popen.rb' }
+
+ context 'when the merge request exists' do
+ context 'when the user can view the merge request' do
+ context 'when the path exists in the diff' do
+ it 'enables diff notes' do
+ diff_for_path(old_path: existing_path, new_path: existing_path)
+
+ expect(assigns(:diff_notes_disabled)).to be_falsey
+ expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'MergeRequest',
+ noteable_id: merge_request.id)
+ end
+
+ it 'only renders the diffs for the path given' do
+ expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
+ expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
+ meth.call(diffs)
+ end
+
+ diff_for_path(old_path: existing_path, new_path: existing_path)
+ end
+ end
+
+ context 'when the path does not exist in the diff' do
+ before do
+ diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb')
+ end
+
+ it 'returns a 404' do
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ context 'when the user cannot view the merge request' do
+ before do
+ project.team.truncate
+ diff_for_path(old_path: existing_path, new_path: existing_path)
+ end
+
+ it 'returns a 404' do
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ context 'when the merge request does not exist' do
+ before do
+ diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path)
+ end
+
+ it 'returns a 404' do
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when the merge request belongs to a different project' do
+ let(:other_project) { create(:empty_project) }
+
+ before do
+ other_project.team << [user, :master]
+ diff_for_path(old_path: existing_path, new_path: existing_path, project_id: other_project)
+ end
+
+ it 'returns a 404' do
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 6817c2652fd..2fce4b7a85f 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -14,53 +14,6 @@ describe Projects::MergeRequestsController do
sign_in(user)
end
- describe 'GET new' do
- context 'merge request that removes a submodule' do
- render_views
-
- let(:fork_project) { create(:forked_project_with_submodules) }
-
- before do
- fork_project.team << [user, :master]
- end
-
- context 'when rendering HTML response' do
- it 'renders new merge request widget template' do
- submit_new_merge_request
-
- expect(response).to be_success
- end
- end
-
- context 'when rendering JSON response' do
- before do
- create(:ci_pipeline, sha: fork_project.commit('remove-submodule').id,
- ref: 'remove-submodule',
- project: fork_project)
- end
-
- it 'renders JSON including serialized pipelines' do
- submit_new_merge_request(format: :json)
-
- expect(response).to be_ok
- expect(json_response).to have_key 'pipelines'
- expect(json_response['pipelines']).not_to be_empty
- end
- end
- end
-
- def submit_new_merge_request(format: :html)
- get :new,
- namespace_id: fork_project.namespace.to_param,
- project_id: fork_project,
- merge_request: {
- source_branch: 'remove-submodule',
- target_branch: 'master'
- },
- format: format
- end
- end
-
describe 'GET commit_change_content' do
it 'renders commit_change_content template' do
get :commit_change_content,
@@ -486,7 +439,7 @@ describe Projects::MergeRequestsController do
delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid
expect(response).to have_http_status(302)
- expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./).now
+ expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./)
end
it 'delegates the update of the todos count cache to TodoService' do
@@ -497,234 +450,6 @@ describe Projects::MergeRequestsController do
end
end
- describe 'GET diffs' do
- def go(extra_params = {})
- params = {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: merge_request.iid
- }
-
- get :diffs, params.merge(extra_params)
- end
-
- it_behaves_like "loads labels", :diffs
-
- context 'with default params' do
- context 'as html' do
- before do
- go(format: 'html')
- end
-
- it 'renders the diff template' do
- expect(response).to render_template('diffs')
- end
- end
-
- context 'as json' do
- before do
- go(format: 'json')
- end
-
- it 'renders the diffs template to a string' do
- expect(response).to render_template('projects/merge_requests/show/_diffs')
- expect(json_response).to have_key('html')
- end
- end
-
- context 'with forked projects with submodules' do
- render_views
-
- let(:project) { create(:project) }
- let(:fork_project) { create(:forked_project_with_submodules) }
- let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
-
- before do
- fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
- fork_project.save
- merge_request.reload
- go(format: 'json')
- end
-
- it 'renders' do
- expect(response).to be_success
- expect(response.body).to have_content('Subproject commit')
- end
- end
- end
-
- context 'with ignore_whitespace_change' do
- context 'as html' do
- before do
- go(format: 'html', w: 1)
- end
-
- it 'renders the diff template' do
- expect(response).to render_template('diffs')
- end
- end
-
- context 'as json' do
- before do
- go(format: 'json', w: 1)
- end
-
- it 'renders the diffs template to a string' do
- expect(response).to render_template('projects/merge_requests/show/_diffs')
- expect(json_response).to have_key('html')
- end
- end
- end
-
- context 'with view' do
- before do
- go(view: 'parallel')
- end
-
- it 'saves the preferred diff view in a cookie' do
- expect(response.cookies['diff_view']).to eq('parallel')
- end
- end
- end
-
- describe 'GET diff_for_path' do
- def diff_for_path(extra_params = {})
- params = {
- namespace_id: project.namespace.to_param,
- project_id: project
- }
-
- get :diff_for_path, params.merge(extra_params)
- end
-
- context 'when an ID param is passed' do
- let(:existing_path) { 'files/ruby/popen.rb' }
-
- context 'when the merge request exists' do
- context 'when the user can view the merge request' do
- context 'when the path exists in the diff' do
- it 'enables diff notes' do
- diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path)
-
- expect(assigns(:diff_notes_disabled)).to be_falsey
- expect(assigns(:new_diff_note_attrs)).to eq(noteable_type: 'MergeRequest',
- noteable_id: merge_request.id)
- end
-
- it 'only renders the diffs for the path given' do
- expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
- expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
- meth.call(diffs)
- end
-
- diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path)
- end
- end
-
- context 'when the path does not exist in the diff' do
- before do
- diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb')
- end
-
- it 'returns a 404' do
- expect(response).to have_http_status(404)
- end
- end
- end
-
- context 'when the user cannot view the merge request' do
- before do
- project.team.truncate
- diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path)
- end
-
- it 'returns a 404' do
- expect(response).to have_http_status(404)
- end
- end
- end
-
- context 'when the merge request does not exist' do
- before do
- diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path)
- end
-
- it 'returns a 404' do
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when the merge request belongs to a different project' do
- let(:other_project) { create(:empty_project) }
-
- before do
- other_project.team << [user, :master]
- diff_for_path(id: merge_request.iid, old_path: existing_path, new_path: existing_path, project_id: other_project)
- end
-
- it 'returns a 404' do
- expect(response).to have_http_status(404)
- end
- end
- end
-
- context 'when source and target params are passed' do
- let(:existing_path) { 'files/ruby/feature.rb' }
-
- context 'when both branches are in the same project' do
- it 'disables diff notes' do
- diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
-
- expect(assigns(:diff_notes_disabled)).to be_truthy
- end
-
- it 'only renders the diffs for the path given' do
- expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
- expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
- meth.call(diffs)
- end
-
- diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_branch: 'feature', target_branch: 'master' })
- end
- end
-
- context 'when the source branch is in a different project to the target' do
- let(:other_project) { create(:project) }
-
- before do
- other_project.team << [user, :master]
- end
-
- context 'when the path exists in the diff' do
- it 'disables diff notes' do
- diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
-
- expect(assigns(:diff_notes_disabled)).to be_truthy
- end
-
- it 'only renders the diffs for the path given' do
- expect(controller).to receive(:render_diff_for_path).and_wrap_original do |meth, diffs|
- expect(diffs.diff_files.map(&:new_path)).to contain_exactly(existing_path)
- meth.call(diffs)
- end
-
- diff_for_path(old_path: existing_path, new_path: existing_path, merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
- end
- end
-
- context 'when the path does not exist in the diff' do
- before do
- diff_for_path(old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb', merge_request: { source_project: other_project, source_branch: 'feature', target_branch: 'master' })
- end
-
- it 'returns a 404' do
- expect(response).to have_http_status(404)
- end
- end
- end
- end
- end
-
describe 'GET commits' do
def go(format: 'html')
get :commits,
@@ -734,23 +459,11 @@ describe Projects::MergeRequestsController do
format: format
end
- it_behaves_like "loads labels", :commits
+ it 'renders the commits template to a string' do
+ go format: 'json'
- context 'as html' do
- it 'renders the show template' do
- go
-
- expect(response).to render_template('show')
- end
- end
-
- context 'as json' do
- it 'renders the commits template to a string' do
- go format: 'json'
-
- expect(response).to render_template('projects/merge_requests/show/_commits')
- expect(json_response).to have_key('html')
- end
+ expect(response).to render_template('projects/merge_requests/_commits')
+ expect(json_response).to have_key('html')
end
end
@@ -759,106 +472,17 @@ describe Projects::MergeRequestsController do
create(:ci_pipeline, project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha)
- end
-
- context 'when using HTML format' do
- it_behaves_like "loads labels", :pipelines
- end
- context 'when using JSON format' do
- before do
- get :pipelines,
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: merge_request.iid,
- format: :json
- end
-
- it 'responds with serialized pipelines' do
- expect(json_response).not_to be_empty
- end
- end
- end
-
- describe 'GET conflicts' do
- context 'when the conflicts cannot be resolved in the UI' do
- before do
- allow_any_instance_of(Gitlab::Conflict::Parser)
- .to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
-
- get :conflicts,
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid,
- format: 'json'
- end
-
- it 'returns a 200 status code' do
- expect(response).to have_http_status(:ok)
- end
-
- it 'returns JSON with a message' do
- expect(json_response.keys).to contain_exactly('message', 'type')
- end
+ get :pipelines,
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid,
+ format: :json
end
- context 'with valid conflicts' do
- before do
- get :conflicts,
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid,
- format: 'json'
- end
-
- it 'matches the schema' do
- expect(response).to match_response_schema('conflicts')
- end
-
- it 'includes meta info about the MR' do
- expect(json_response['commit_message']).to include('Merge branch')
- expect(json_response['commit_sha']).to match(/\h{40}/)
- expect(json_response['source_branch']).to eq(merge_request_with_conflicts.source_branch)
- expect(json_response['target_branch']).to eq(merge_request_with_conflicts.target_branch)
- end
-
- it 'includes each file that has conflicts' do
- filenames = json_response['files'].map { |file| file['new_path'] }
-
- expect(filenames).to contain_exactly('files/ruby/popen.rb', 'files/ruby/regex.rb')
- end
-
- it 'splits files into sections with lines' do
- json_response['files'].each do |file|
- file['sections'].each do |section|
- expect(section).to include('conflict', 'lines')
-
- section['lines'].each do |line|
- if section['conflict']
- expect(line['type']).to be_in(%w(old new))
- expect(line.values_at('old_line', 'new_line')).to contain_exactly(nil, a_kind_of(Integer))
- else
- if line['type'].nil?
- expect(line['old_line']).not_to eq(nil)
- expect(line['new_line']).not_to eq(nil)
- else
- expect(line['type']).to eq('match')
- expect(line['old_line']).to eq(nil)
- expect(line['new_line']).to eq(nil)
- end
- end
- end
- end
- end
- end
-
- it 'has unique section IDs across files' do
- section_ids = json_response['files'].flat_map do |file|
- file['sections'].map { |section| section['id'] }.compact
- end
-
- expect(section_ids.uniq).to eq(section_ids)
- end
+ it 'responds with serialized pipelines' do
+ expect(json_response['pipelines']).not_to be_empty
+ expect(json_response['count']['all']).to eq 1
end
end
@@ -913,215 +537,6 @@ describe Projects::MergeRequestsController do
end
end
- describe 'GET conflict_for_path' do
- def conflict_for_path(path)
- get :conflict_for_path,
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid,
- old_path: path,
- new_path: path,
- format: 'json'
- end
-
- context 'when the conflicts cannot be resolved in the UI' do
- before do
- allow_any_instance_of(Gitlab::Conflict::Parser)
- .to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
-
- conflict_for_path('files/ruby/regex.rb')
- end
-
- it 'returns a 404 status code' do
- expect(response).to have_http_status(:not_found)
- end
- end
-
- context 'when the file does not exist cannot be resolved in the UI' do
- before do
- conflict_for_path('files/ruby/regexp.rb')
- end
-
- it 'returns a 404 status code' do
- expect(response).to have_http_status(:not_found)
- end
- end
-
- context 'with an existing file' do
- let(:path) { 'files/ruby/regex.rb' }
-
- before do
- conflict_for_path(path)
- end
-
- it 'returns a 200 status code' do
- expect(response).to have_http_status(:ok)
- end
-
- it 'returns the file in JSON format' do
- content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
- .file_for_path(path, path)
- .content
-
- expect(json_response).to include('old_path' => path,
- 'new_path' => path,
- 'blob_icon' => 'file-text-o',
- 'blob_path' => a_string_ending_with(path),
- 'blob_ace_mode' => 'ruby',
- 'content' => content)
- end
- end
- end
-
- context 'POST resolve_conflicts' do
- let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
-
- def resolve_conflicts(files)
- post :resolve_conflicts,
- namespace_id: merge_request_with_conflicts.project.namespace.to_param,
- project_id: merge_request_with_conflicts.project,
- id: merge_request_with_conflicts.iid,
- format: 'json',
- files: files,
- commit_message: 'Commit message'
- end
-
- context 'with valid params' do
- before do
- resolved_files = [
- {
- 'new_path' => 'files/ruby/popen.rb',
- 'old_path' => 'files/ruby/popen.rb',
- 'sections' => {
- '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
- }
- }, {
- 'new_path' => 'files/ruby/regex.rb',
- 'old_path' => 'files/ruby/regex.rb',
- 'sections' => {
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
- }
- }
- ]
-
- resolve_conflicts(resolved_files)
- end
-
- it 'creates a new commit on the branch' do
- expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
- expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
- end
-
- it 'returns an OK response' do
- expect(response).to have_http_status(:ok)
- end
- end
-
- context 'when sections are missing' do
- before do
- resolved_files = [
- {
- 'new_path' => 'files/ruby/popen.rb',
- 'old_path' => 'files/ruby/popen.rb',
- 'sections' => {
- '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
- }
- }, {
- 'new_path' => 'files/ruby/regex.rb',
- 'old_path' => 'files/ruby/regex.rb',
- 'sections' => {
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head'
- }
- }
- ]
-
- resolve_conflicts(resolved_files)
- end
-
- it 'returns a 400 error' do
- expect(response).to have_http_status(:bad_request)
- end
-
- it 'has a message with the name of the first missing section' do
- expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
- end
-
- it 'does not create a new commit' do
- expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
- end
- end
-
- context 'when files are missing' do
- before do
- resolved_files = [
- {
- 'new_path' => 'files/ruby/regex.rb',
- 'old_path' => 'files/ruby/regex.rb',
- 'sections' => {
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
- }
- }
- ]
-
- resolve_conflicts(resolved_files)
- end
-
- it 'returns a 400 error' do
- expect(response).to have_http_status(:bad_request)
- end
-
- it 'has a message with the name of the missing file' do
- expect(json_response['message']).to include('files/ruby/popen.rb')
- end
-
- it 'does not create a new commit' do
- expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
- end
- end
-
- context 'when a file has identical content to the conflict' do
- before do
- content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
- .file_for_path('files/ruby/popen.rb', 'files/ruby/popen.rb')
- .content
-
- resolved_files = [
- {
- 'new_path' => 'files/ruby/popen.rb',
- 'old_path' => 'files/ruby/popen.rb',
- 'content' => content
- }, {
- 'new_path' => 'files/ruby/regex.rb',
- 'old_path' => 'files/ruby/regex.rb',
- 'sections' => {
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
- }
- }
- ]
-
- resolve_conflicts(resolved_files)
- end
-
- it 'returns a 400 error' do
- expect(response).to have_http_status(:bad_request)
- end
-
- it 'has a message with the path of the problem file' do
- expect(json_response['message']).to include('files/ruby/popen.rb')
- end
-
- it 'does not create a new commit' do
- expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
- end
- end
- end
-
describe 'POST assign_related_issues' do
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 84a61b2784e..bb5a340cd96 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -31,6 +31,40 @@ describe Projects::MilestonesController do
end
end
+ describe "#index" do
+ context "as html" do
+ before do
+ get :index, namespace_id: project.namespace.id, project_id: project.id
+ end
+
+ it "queries only projects milestones" do
+ milestones = assigns(:milestones)
+
+ expect(milestones.count).to eq(1)
+ expect(milestones.where(project_id: nil)).to be_empty
+ end
+ end
+
+ context "as json" do
+ let!(:group) { create(:group, :public) }
+ let!(:group_milestone) { create(:milestone, group: group) }
+ let!(:group_member) { create(:group_member, group: group, user: user) }
+
+ before do
+ project.update(namespace: group)
+ get :index, namespace_id: project.namespace.id, project_id: project.id, format: :json
+ end
+
+ it "queries projects milestones and groups milestones" do
+ milestones = assigns(:milestones)
+
+ expect(milestones.count).to eq(2)
+ expect(milestones.where(project_id: nil).first).to eq(group_milestone)
+ expect(milestones.where(group_id: nil).first).to eq(milestone)
+ end
+ end
+ end
+
describe "#destroy" do
it "removes milestone" do
expect(issue.milestone_id).to eq(milestone.id)
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 45f4cf9180d..3b88d5b0d7d 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -131,7 +131,7 @@ describe Projects::NotesController do
before do
sign_in(user)
- project.team << [user, :developer]
+ project.add_developer(user)
end
it "returns status 302 for html" do
@@ -165,6 +165,66 @@ describe Projects::NotesController do
expect(response).to have_http_status(302)
end
end
+
+ context 'when creating a commit comment from an MR fork' do
+ let(:project) { create(:project) }
+
+ let(:fork_project) do
+ create(:project).tap do |fork|
+ create(:forked_project_link, forked_to_project: fork, forked_from_project: project)
+ end
+ end
+
+ let(:merge_request) do
+ create(:merge_request, source_project: fork_project, target_project: project, source_branch: 'feature', target_branch: 'master')
+ end
+
+ let(:existing_comment) do
+ create(:note_on_commit, note: 'a note', project: fork_project, commit_id: merge_request.commit_shas.first)
+ end
+
+ def post_create(extra_params = {})
+ post :create, {
+ note: { note: 'some other note' },
+ namespace_id: project.namespace,
+ project_id: project,
+ target_type: 'merge_request',
+ target_id: merge_request.id,
+ note_project_id: fork_project.id,
+ in_reply_to_discussion_id: existing_comment.discussion_id
+ }.merge(extra_params)
+ end
+
+ context 'when the note_project_id is not correct' do
+ it 'returns a 404' do
+ post_create(note_project_id: Project.maximum(:id).succ)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when the user has no access to the fork' do
+ it 'returns a 404' do
+ post_create
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when the user has access to the fork' do
+ let(:discussion) { fork_project.notes.find_discussion(existing_comment.discussion_id) }
+
+ before do
+ fork_project.add_developer(user)
+
+ existing_comment
+ end
+
+ it 'creates the note' do
+ expect { post_create }.to change { fork_project.notes.count }.by(1)
+ end
+ end
+ end
end
describe 'DELETE destroy' do
diff --git a/spec/controllers/projects/pages_domains_controller_spec.rb b/spec/controllers/projects/pages_domains_controller_spec.rb
index 33853c4b9d0..920189be381 100644
--- a/spec/controllers/projects/pages_domains_controller_spec.rb
+++ b/spec/controllers/projects/pages_domains_controller_spec.rb
@@ -46,7 +46,7 @@ describe Projects::PagesDomainsController do
post(:create, request_params.merge(pages_domain: pages_domain_params))
end.to change { PagesDomain.count }.by(1)
- expect(response).to redirect_to(namespace_project_pages_path(project.namespace, project))
+ expect(response).to redirect_to(project_pages_path(project))
end
end
@@ -56,7 +56,7 @@ describe Projects::PagesDomainsController do
delete(:destroy, request_params.merge(id: pages_domain.domain))
end.to change { PagesDomain.count }.by(-1)
- expect(response).to redirect_to(namespace_project_pages_path(project.namespace, project))
+ expect(response).to redirect_to(project_pages_path(project))
end
end
diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
index f8f95dd9bc8..41bf5580993 100644
--- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb
+++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Projects::PipelineSchedulesController do
+ include AccessMatchersForController
+
set(:project) { create(:empty_project, :public) }
let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) }
@@ -17,6 +19,14 @@ describe Projects::PipelineSchedulesController do
expect(response).to render_template(:index)
end
+ it 'avoids N + 1 queries' do
+ control_count = ActiveRecord::QueryRecorder.new { visit_pipelines_schedules }.count
+
+ create_list(:ci_pipeline_schedule, 2, project: project)
+
+ expect { visit_pipelines_schedules }.not_to exceed_query_limit(control_count)
+ end
+
context 'when the scope is set to active' do
let(:scope) { 'active' }
@@ -36,20 +46,321 @@ describe Projects::PipelineSchedulesController do
end
end
- describe 'GET edit' do
- let(:user) { create(:user) }
+ describe 'GET #new' do
+ set(:user) { create(:user) }
before do
- project.add_master(user)
-
+ project.add_developer(user)
sign_in(user)
end
- it 'loads the pipeline schedule' do
- get :edit, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
+ it 'initializes a pipeline schedule model' do
+ get :new, namespace_id: project.namespace.to_param, project_id: project
expect(response).to have_http_status(:ok)
- expect(assigns(:schedule)).to eq(pipeline_schedule)
+ expect(assigns(:schedule)).to be_a_new(Ci::PipelineSchedule)
+ end
+ end
+
+ describe 'POST #create' do
+ describe 'functionality' do
+ set(:user) { create(:user) }
+
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
+
+ let(:basic_param) do
+ attributes_for(:ci_pipeline_schedule)
+ end
+
+ context 'when variables_attributes has one variable' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ key: 'AAA', value: 'AAA123' }]
+ })
+ end
+
+ it 'creates a new schedule' do
+ expect { go }
+ .to change { Ci::PipelineSchedule.count }.by(1)
+ .and change { Ci::PipelineScheduleVariable.count }.by(1)
+
+ expect(response).to have_http_status(:found)
+
+ Ci::PipelineScheduleVariable.last.tap do |v|
+ expect(v.key).to eq("AAA")
+ expect(v.value).to eq("AAA123")
+ end
+ end
+ end
+
+ context 'when variables_attributes has two variables and duplicted' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }]
+ })
+ end
+
+ it 'returns an error that the keys of variable are duplicated' do
+ expect { go }
+ .to change { Ci::PipelineSchedule.count }.by(0)
+ .and change { Ci::PipelineScheduleVariable.count }.by(0)
+
+ expect(assigns(:schedule).errors['variables']).not_to be_empty
+ end
+ end
+ end
+
+ describe 'security' do
+ let(:schedule) { attributes_for(:ci_pipeline_schedule) }
+
+ it { expect { go }.to be_allowed_for(:admin) }
+ it { expect { go }.to be_allowed_for(:owner).of(project) }
+ it { expect { go }.to be_allowed_for(:master).of(project) }
+ it { expect { go }.to be_allowed_for(:developer).of(project) }
+ it { expect { go }.to be_denied_for(:reporter).of(project) }
+ it { expect { go }.to be_denied_for(:guest).of(project) }
+ it { expect { go }.to be_denied_for(:user) }
+ it { expect { go }.to be_denied_for(:external) }
+ it { expect { go }.to be_denied_for(:visitor) }
+ end
+
+ def go
+ post :create, namespace_id: project.namespace.to_param, project_id: project, schedule: schedule
+ end
+ end
+
+ describe 'PUT #update' do
+ describe 'functionality' do
+ set(:user) { create(:user) }
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
+
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
+
+ context 'when a pipeline schedule has no variables' do
+ let(:basic_param) do
+ { description: 'updated_desc', cron: '0 1 * * *', cron_timezone: 'UTC', ref: 'patch-x', active: true }
+ end
+
+ context 'when params include one variable' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ key: 'AAA', value: 'AAA123' }]
+ })
+ end
+
+ it 'inserts new variable to the pipeline schedule' do
+ expect { go }.to change { Ci::PipelineScheduleVariable.count }.by(1)
+
+ pipeline_schedule.reload
+ expect(response).to have_http_status(:found)
+ expect(pipeline_schedule.variables.last.key).to eq('AAA')
+ expect(pipeline_schedule.variables.last.value).to eq('AAA123')
+ end
+ end
+
+ context 'when params include two duplicated variables' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }]
+ })
+ end
+
+ it 'returns an error that variables are duplciated' do
+ go
+
+ expect(assigns(:schedule).errors['variables']).not_to be_empty
+ end
+ end
+ end
+
+ context 'when a pipeline schedule has one variable' do
+ let(:basic_param) do
+ { description: 'updated_desc', cron: '0 1 * * *', cron_timezone: 'UTC', ref: 'patch-x', active: true }
+ end
+
+ let!(:pipeline_schedule_variable) do
+ create(:ci_pipeline_schedule_variable,
+ key: 'CCC', pipeline_schedule: pipeline_schedule)
+ end
+
+ context 'when adds a new variable' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ key: 'AAA', value: 'AAA123' }]
+ })
+ end
+
+ it 'adds the new variable' do
+ expect { go }.to change { Ci::PipelineScheduleVariable.count }.by(1)
+
+ pipeline_schedule.reload
+ expect(pipeline_schedule.variables.last.key).to eq('AAA')
+ end
+ end
+
+ context 'when adds a new duplicated variable' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ key: 'CCC', value: 'AAA123' }]
+ })
+ end
+
+ it 'returns an error' do
+ expect { go }.not_to change { Ci::PipelineScheduleVariable.count }
+
+ pipeline_schedule.reload
+ expect(assigns(:schedule).errors['variables']).not_to be_empty
+ end
+ end
+
+ context 'when updates a variable' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ id: pipeline_schedule_variable.id, value: 'new_value' }]
+ })
+ end
+
+ it 'updates the variable' do
+ expect { go }.not_to change { Ci::PipelineScheduleVariable.count }
+
+ pipeline_schedule_variable.reload
+ expect(pipeline_schedule_variable.value).to eq('new_value')
+ end
+ end
+
+ context 'when deletes a variable' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ id: pipeline_schedule_variable.id, _destroy: true }]
+ })
+ end
+
+ it 'delete the existsed variable' do
+ expect { go }.to change { Ci::PipelineScheduleVariable.count }.by(-1)
+ end
+ end
+
+ context 'when deletes and creates a same key simultaneously' do
+ let(:schedule) do
+ basic_param.merge({
+ variables_attributes: [{ id: pipeline_schedule_variable.id, _destroy: true },
+ { key: 'CCC', value: 'CCC123' }]
+ })
+ end
+
+ it 'updates the variable' do
+ expect { go }.not_to change { Ci::PipelineScheduleVariable.count }
+
+ pipeline_schedule.reload
+ expect(pipeline_schedule.variables.last.key).to eq('CCC')
+ expect(pipeline_schedule.variables.last.value).to eq('CCC123')
+ end
+ end
+ end
+ end
+
+ describe 'security' do
+ let(:schedule) { { description: 'updated_desc' } }
+
+ it { expect { go }.to be_allowed_for(:admin) }
+ it { expect { go }.to be_allowed_for(:owner).of(project) }
+ it { expect { go }.to be_allowed_for(:master).of(project) }
+ it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) }
+ it { expect { go }.to be_denied_for(:reporter).of(project) }
+ it { expect { go }.to be_denied_for(:guest).of(project) }
+ it { expect { go }.to be_denied_for(:user) }
+ it { expect { go }.to be_denied_for(:external) }
+ it { expect { go }.to be_denied_for(:visitor) }
+
+ context 'when a developer created a pipeline schedule' do
+ let(:developer_1) { create(:user) }
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: developer_1) }
+
+ before do
+ project.add_developer(developer_1)
+ end
+
+ it { expect { go }.to be_allowed_for(developer_1) }
+ it { expect { go }.to be_denied_for(:developer).of(project) }
+ it { expect { go }.to be_allowed_for(:master).of(project) }
+ end
+
+ context 'when a master created a pipeline schedule' do
+ let(:master_1) { create(:user) }
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: master_1) }
+
+ before do
+ project.add_master(master_1)
+ end
+
+ it { expect { go }.to be_allowed_for(master_1) }
+ it { expect { go }.to be_allowed_for(:master).of(project) }
+ it { expect { go }.to be_denied_for(:developer).of(project) }
+ end
+ end
+
+ def go
+ put :update, namespace_id: project.namespace.to_param,
+ project_id: project, id: pipeline_schedule,
+ schedule: schedule
+ end
+ end
+
+ describe 'GET #edit' do
+ describe 'functionality' do
+ let(:user) { create(:user) }
+
+ before do
+ project.add_master(user)
+ sign_in(user)
+ end
+
+ it 'loads the pipeline schedule' do
+ get :edit, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
+
+ expect(response).to have_http_status(:ok)
+ expect(assigns(:schedule)).to eq(pipeline_schedule)
+ end
+ end
+
+ describe 'security' do
+ it { expect { go }.to be_allowed_for(:admin) }
+ it { expect { go }.to be_allowed_for(:owner).of(project) }
+ it { expect { go }.to be_allowed_for(:master).of(project) }
+ it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) }
+ it { expect { go }.to be_denied_for(:reporter).of(project) }
+ it { expect { go }.to be_denied_for(:guest).of(project) }
+ it { expect { go }.to be_denied_for(:user) }
+ it { expect { go }.to be_denied_for(:external) }
+ it { expect { go }.to be_denied_for(:visitor) }
+ end
+
+ def go
+ get :edit, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
+ end
+ end
+
+ describe 'GET #take_ownership' do
+ describe 'security' do
+ it { expect { go }.to be_allowed_for(:admin) }
+ it { expect { go }.to be_allowed_for(:owner).of(project) }
+ it { expect { go }.to be_allowed_for(:master).of(project) }
+ it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) }
+ it { expect { go }.to be_denied_for(:reporter).of(project) }
+ it { expect { go }.to be_denied_for(:guest).of(project) }
+ it { expect { go }.to be_denied_for(:user) }
+ it { expect { go }.to be_denied_for(:external) }
+ it { expect { go }.to be_denied_for(:visitor) }
+ end
+
+ def go
+ post :take_ownership, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
end
end
@@ -65,7 +376,7 @@ describe Projects::PipelineSchedulesController do
end
it 'does not delete the pipeline schedule' do
- expect(response).not_to have_http_status(:ok)
+ expect(response).to have_http_status(:not_found)
end
end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 734532668d3..c8de275ca3e 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -8,6 +8,7 @@ describe Projects::PipelinesController do
let(:feature) { ProjectFeature::DISABLED }
before do
+ stub_not_protect_default_branch
project.add_developer(user)
project.project_feature.update(
builds_access_level: feature)
@@ -158,7 +159,7 @@ describe Projects::PipelinesController do
context 'when builds are enabled' do
let(:feature) { ProjectFeature::ENABLED }
-
+
it 'retries a pipeline without returning any content' do
expect(response).to have_http_status(:no_content)
expect(build.reload).to be_retried
@@ -175,7 +176,7 @@ describe Projects::PipelinesController do
describe 'POST cancel.json' do
let!(:pipeline) { create(:ci_pipeline, project: project) }
let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
-
+
before do
post :cancel, namespace_id: project.namespace,
project_id: project,
@@ -185,7 +186,7 @@ describe Projects::PipelinesController do
context 'when builds are enabled' do
let(:feature) { ProjectFeature::ENABLED }
-
+
it 'cancels a pipeline without returning any content' do
expect(response).to have_http_status(:no_content)
expect(pipeline.reload).to be_canceled
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index f2b59ba82ca..8671d7a78dd 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -5,11 +5,10 @@ describe Projects::ProjectMembersController do
let(:project) { create(:empty_project, :public, :access_requestable) }
describe 'GET index' do
- it 'should have the settings/members address with a 302 status code' do
+ it 'should have the project_members address with a 200 status code' do
get :index, namespace_id: project.namespace, project_id: project
- expect(response).to have_http_status(302)
- expect(response.location).to include namespace_project_settings_members_path(project.namespace, project)
+ expect(response).to have_http_status(200)
end
end
@@ -50,7 +49,7 @@ describe Projects::ProjectMembersController do
access_level: Gitlab::Access::GUEST
expect(response).to set_flash.to 'Users were successfully added.'
- expect(response).to redirect_to(namespace_project_settings_members_path(project.namespace, project))
+ expect(response).to redirect_to(project_project_members_path(project))
end
it 'adds no user to members' do
@@ -62,7 +61,7 @@ describe Projects::ProjectMembersController do
access_level: Gitlab::Access::GUEST
expect(response).to set_flash.to 'Message'
- expect(response).to redirect_to(namespace_project_settings_members_path(project.namespace, project))
+ expect(response).to redirect_to(project_project_members_path(project))
end
end
end
@@ -111,7 +110,7 @@ describe Projects::ProjectMembersController do
id: member
expect(response).to redirect_to(
- namespace_project_settings_members_path(project.namespace, project)
+ project_project_members_path(project)
)
expect(project.members).not_to include member
end
@@ -183,7 +182,7 @@ describe Projects::ProjectMembersController do
project_id: project
expect(response).to set_flash.to 'Your access request to the project has been withdrawn.'
- expect(response).to redirect_to(namespace_project_path(project.namespace, project))
+ expect(response).to redirect_to(project_path(project))
expect(project.requesters).to be_empty
expect(project.users).not_to include user
end
@@ -202,7 +201,7 @@ describe Projects::ProjectMembersController do
expect(response).to set_flash.to 'Your request for access has been queued for review.'
expect(response).to redirect_to(
- namespace_project_path(project.namespace, project)
+ project_path(project)
)
expect(project.requesters.exists?(user_id: user)).to be_truthy
expect(project.users).not_to include user
@@ -253,7 +252,7 @@ describe Projects::ProjectMembersController do
id: member
expect(response).to redirect_to(
- namespace_project_settings_members_path(project.namespace, project)
+ project_project_members_path(project)
)
expect(project.members).to include member
end
@@ -290,7 +289,7 @@ describe Projects::ProjectMembersController do
expect(project.team_members).to include member
expect(response).to set_flash.to 'Successfully imported'
expect(response).to redirect_to(
- namespace_project_settings_members_path(project.namespace, project)
+ project_project_members_path(project)
)
end
end
diff --git a/spec/controllers/projects/prometheus_controller_spec.rb b/spec/controllers/projects/prometheus_controller_spec.rb
new file mode 100644
index 00000000000..eddf7275975
--- /dev/null
+++ b/spec/controllers/projects/prometheus_controller_spec.rb
@@ -0,0 +1,59 @@
+require('spec_helper')
+
+describe Projects::PrometheusController do
+ let(:user) { create(:user) }
+ let!(:project) { create(:empty_project) }
+
+ let(:prometheus_service) { double('prometheus_service') }
+
+ before do
+ allow(controller).to receive(:project).and_return(project)
+ allow(project).to receive(:prometheus_service).and_return(prometheus_service)
+
+ project.add_master(user)
+ sign_in(user)
+ end
+
+ describe 'GET #active_metrics' do
+ context 'when prometheus metrics are enabled' do
+ context 'when data is not present' do
+ before do
+ allow(prometheus_service).to receive(:matched_metrics).and_return({})
+ end
+
+ it 'returns no content response' do
+ get :active_metrics, project_params(format: :json)
+
+ expect(response).to have_http_status(204)
+ end
+ end
+
+ context 'when data is available' do
+ let(:sample_response) { { some_data: 1 } }
+
+ before do
+ allow(prometheus_service).to receive(:matched_metrics).and_return(sample_response)
+ end
+
+ it 'returns no content response' do
+ get :active_metrics, project_params(format: :json)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to eq(sample_response.deep_stringify_keys)
+ end
+ end
+
+ context 'when requesting non json response' do
+ it 'returns not found response' do
+ get :active_metrics, project_params
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+ end
+
+ def project_params(opts = {})
+ opts.reverse_merge(namespace_id: project.namespace, project_id: project)
+ end
+end
diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb
new file mode 100644
index 00000000000..a823516830e
--- /dev/null
+++ b/spec/controllers/projects/registry/tags_controller_spec.rb
@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+describe Projects::Registry::TagsController do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, :private) }
+
+ before do
+ sign_in(user)
+ stub_container_registry_config(enabled: true)
+ end
+
+ context 'when user has access to registry' do
+ before do
+ project.add_developer(user)
+ end
+
+ describe 'POST destroy' do
+ context 'when there is matching tag present' do
+ before do
+ stub_container_registry_tags(repository: /image/, tags: %w[rc1 test.])
+ end
+
+ let(:repository) do
+ create(:container_repository, name: 'image', project: project)
+ end
+
+ it 'makes it possible to delete regular tag' do
+ expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete)
+
+ destroy_tag('rc1')
+ end
+
+ it 'makes it possible to delete a tag that ends with a dot' do
+ expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete)
+
+ destroy_tag('test.')
+ end
+ end
+ end
+ end
+
+ def destroy_tag(name)
+ post :destroy, namespace_id: project.namespace,
+ project_id: project,
+ repository_id: repository,
+ id: name
+ end
+end
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 4dc227a36d4..5a9d8a75f3e 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -79,7 +79,7 @@ describe Projects::ServicesController do
put :update,
namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: { active: true }
- expect(response).to redirect_to(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(response).to redirect_to(project_settings_integrations_path(project))
expect(flash[:notice]).to eq 'HipChat activated.'
end
end
diff --git a/spec/controllers/projects/settings/members_controller_spec.rb b/spec/controllers/projects/settings/members_controller_spec.rb
deleted file mode 100644
index 076d6cd9c6e..00000000000
--- a/spec/controllers/projects/settings/members_controller_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require('spec_helper')
-
-describe Projects::Settings::MembersController do
- let(:project) { create(:empty_project, :public, :access_requestable) }
-
- describe 'GET show' do
- it 'renders show with 200 status code' do
- get :show, namespace_id: project.namespace, project_id: project
-
- expect(response).to have_http_status(200)
- expect(response).to render_template(:show)
- end
- end
-end
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index ec0b7f8c967..cc444f31797 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -148,7 +148,7 @@ describe Projects::SnippetsController do
{ spam_log_id: spam_logs.last.id,
recaptcha_verification: true })
- expect(response).to redirect_to(Snippet.last)
+ expect(response).to redirect_to(project_snippet_path(project, Snippet.last))
end
end
end
@@ -228,7 +228,7 @@ describe Projects::SnippetsController do
{ spam_log_id: spam_logs.last.id,
recaptcha_verification: true })
- expect(response).to redirect_to(snippet)
+ expect(response).to redirect_to(project_snippet_path(project, snippet))
end
end
end
@@ -273,7 +273,7 @@ describe Projects::SnippetsController do
{ spam_log_id: spam_logs.last.id,
recaptcha_verification: true })
- expect(response).to redirect_to(snippet)
+ expect(response).to redirect_to(project_snippet_path(project, snippet))
end
end
end
diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb
index 1ecfe48475c..da06fcb7cfb 100644
--- a/spec/controllers/projects/variables_controller_spec.rb
+++ b/spec/controllers/projects/variables_controller_spec.rb
@@ -15,13 +15,13 @@ describe Projects::VariablesController do
post :create, namespace_id: project.namespace.to_param, project_id: project,
variable: { key: "one", value: "two" }
- expect(flash[:notice]).to include 'Variables were successfully updated.'
- expect(response).to redirect_to(namespace_project_settings_ci_cd_path(project.namespace, project))
+ expect(flash[:notice]).to include 'Variable was successfully created.'
+ expect(response).to redirect_to(project_settings_ci_cd_path(project))
end
end
context 'variable is invalid' do
- it 'shows an alert flash message' do
+ it 'renders show' do
post :create, namespace_id: project.namespace.to_param, project_id: project,
variable: { key: "..one", value: "two" }
@@ -35,7 +35,6 @@ describe Projects::VariablesController do
context 'updating a variable with valid characters' do
before do
- variable.project_id = project.id
project.variables << variable
end
@@ -44,7 +43,7 @@ describe Projects::VariablesController do
id: variable.id, variable: { key: variable.key, value: 'two' }
expect(flash[:notice]).to include 'Variable was successfully updated.'
- expect(response).to redirect_to(namespace_project_variables_path(project.namespace, project))
+ expect(response).to redirect_to(project_variables_path(project))
end
it 'renders the action #show if the variable key is invalid' do
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 240a81367d0..192cca45d99 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -211,24 +211,43 @@ describe ProjectsController do
let(:admin) { create(:admin) }
let(:project) { create(:project, :repository) }
- let(:new_path) { 'renamed_path' }
- let(:project_params) { { path: new_path } }
before do
sign_in(admin)
end
- it "sets the repository to the right path after a rename" do
- controller.instance_variable_set(:@project, project)
+ context 'when only renaming a project path' do
+ it "sets the repository to the right path after a rename" do
+ expect { update_project path: 'renamed_path' }
+ .to change { project.reload.path }
- put :update,
- namespace_id: project.namespace,
- id: project.id,
- project: project_params
+ expect(project.path).to include 'renamed_path'
+ expect(assigns(:repository).path).to include project.path
+ expect(response).to have_http_status(302)
+ end
+ end
- expect(project.repository.path).to include(new_path)
- expect(assigns(:repository).path).to eq(project.repository.path)
- expect(response).to have_http_status(302)
+ context 'when project has container repositories with tags' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: /image/, tags: %w[rc1])
+ create(:container_repository, project: project, name: :image)
+ end
+
+ it 'does not allow to rename the project' do
+ expect { update_project path: 'renamed_path' }
+ .not_to change { project.reload.path }
+
+ expect(controller).to set_flash[:alert].to(/container registry tags/)
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ def update_project(**parameters)
+ put :update,
+ namespace_id: project.namespace.path,
+ id: project.path,
+ project: parameters
end
end
@@ -482,7 +501,7 @@ describe ProjectsController do
it 'redirects to the canonical path (testing non-show action)' do
get :refs, namespace_id: 'foo', id: 'bar'
- expect(response).to redirect_to(refs_namespace_project_path(namespace_id: public_project.namespace, id: public_project))
+ expect(response).to redirect_to(refs_project_path(public_project))
expect(controller).to set_flash[:notice].to(project_moved_message(redirect_route, public_project))
end
end
diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb
index 917bd44c91b..5d2734b8827 100644
--- a/spec/controllers/sent_notifications_controller_spec.rb
+++ b/spec/controllers/sent_notifications_controller_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe SentNotificationsController, type: :controller do
+describe SentNotificationsController do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:sent_notification) { create(:sent_notification, project: project, noteable: issue, recipient: user) }
@@ -23,7 +23,7 @@ describe SentNotificationsController, type: :controller do
end
it 'sets the flash message' do
- expect(controller).to set_flash[:notice].to(/unsubscribed/).now
+ expect(controller).to set_flash[:notice].to(/unsubscribed/)
end
it 'redirects to the login page' do
@@ -83,12 +83,12 @@ describe SentNotificationsController, type: :controller do
end
it 'sets the flash message' do
- expect(controller).to set_flash[:notice].to(/unsubscribed/).now
+ expect(controller).to set_flash[:notice].to(/unsubscribed/)
end
it 'redirects to the issue page' do
expect(response)
- .to redirect_to(namespace_project_issue_path(project.namespace, project, issue))
+ .to redirect_to(project_issue_path(project, issue))
end
end
@@ -109,12 +109,12 @@ describe SentNotificationsController, type: :controller do
end
it 'sets the flash message' do
- expect(controller).to set_flash[:notice].to(/unsubscribed/).now
+ expect(controller).to set_flash[:notice].to(/unsubscribed/)
end
it 'redirects to the merge request page' do
expect(response)
- .to redirect_to(namespace_project_merge_request_path(project.namespace, project, merge_request))
+ .to redirect_to(project_merge_request_path(project, merge_request))
end
end
end
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index bf922260b2f..a22fd8eaf9b 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -1,9 +1,11 @@
require 'spec_helper'
describe SessionsController do
+ include DeviseHelpers
+
describe '#new' do
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
context 'when auto sign-in is enabled' do
@@ -34,7 +36,7 @@ describe SessionsController do
describe '#create' do
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
context 'when using standard authentications' do
@@ -47,7 +49,7 @@ describe SessionsController do
end
end
- context 'when using valid password', :redis do
+ context 'when using valid password', :clean_gitlab_redis_shared_state do
include UserActivitiesHelpers
let(:user) { create(:user) }
@@ -257,7 +259,7 @@ describe SessionsController do
describe '#new' do
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
it 'redirects correctly for referer on same host with params' do
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 430d1208cd1..475ceda11fe 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -186,8 +186,8 @@ describe SnippetsController do
end
context 'when the snippet description contains a file' do
- let(:picture_file) { '/temp/secret56/picture.jpg' }
- let(:text_file) { '/temp/secret78/text.txt' }
+ let(:picture_file) { '/system/temp/secret56/picture.jpg' }
+ let(:text_file) { '/system/temp/secret78/text.txt' }
let(:description) do
"Description with picture: ![picture](/uploads#{picture_file}) and "\
"text: [text.txt](/uploads#{text_file})"
@@ -208,8 +208,8 @@ describe SnippetsController do
snippet = subject
expected_description = "Description with picture: "\
- "![picture](/uploads/personal_snippet/#{snippet.id}/secret56/picture.jpg) and "\
- "text: [text.txt](/uploads/personal_snippet/#{snippet.id}/secret78/text.txt)"
+ "![picture](/uploads/system/personal_snippet/#{snippet.id}/secret56/picture.jpg) and "\
+ "text: [text.txt](/uploads/system/personal_snippet/#{snippet.id}/secret78/text.txt)"
expect(snippet.description).to eq(expected_description)
end
@@ -341,7 +341,7 @@ describe SnippetsController do
{ spam_log_id: spam_logs.last.id,
recaptcha_verification: true })
- expect(response).to redirect_to(snippet)
+ expect(response).to redirect_to(snippet_path(snippet))
end
end
end
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 01a0659479b..96f719e2b82 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -102,7 +102,7 @@ describe UploadsController do
subject
expect(response.body).to match '\"alt\":\"rails_sample\"'
- expect(response.body).to match "\"url\":\"/uploads/temp"
+ expect(response.body).to match "\"url\":\"/uploads/system/temp"
end
it 'does not create an Upload record' do
@@ -119,7 +119,7 @@ describe UploadsController do
subject
expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
- expect(response.body).to match "\"url\":\"/uploads/temp"
+ expect(response.body).to match "\"url\":\"/uploads/system/temp"
end
it 'does not create an Upload record' do
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 842d82cdbe9..7aeb6efd86d 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -80,9 +80,9 @@ describe UsersController do
it 'renders calendar' do
sign_in(user)
- get :calendar, username: user.username
+ get :calendar, username: user.username, format: :json
- expect(response).to render_template('calendar')
+ expect(response).to have_http_status(200)
end
context 'forked project' do
diff --git a/spec/db/production/settings_spec.rb b/spec/db/production/settings_spec.rb
index a9d015e0666..79e67330854 100644
--- a/spec/db/production/settings_spec.rb
+++ b/spec/db/production/settings_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'rainbow/ext/string'
-describe 'seed production settings', lib: true do
+describe 'seed production settings' do
include StubENV
let(:settings_file) { Rails.root.join('db/fixtures/production/010_settings.rb') }
let(:settings) { Gitlab::CurrentSettings.current_application_settings }
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 0cc498f0ce9..5bba1dec7db 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -84,6 +84,10 @@ FactoryGirl.define do
success
end
+ trait :retried do
+ retried true
+ end
+
trait :cancelable do
pending
end
@@ -106,7 +110,7 @@ FactoryGirl.define do
end
after(:build) do |build, evaluator|
- build.project = build.pipeline.project
+ build.project ||= build.pipeline.project
end
factory :ci_not_started_build do
@@ -207,7 +211,8 @@ FactoryGirl.define do
cache: {
key: 'cache_key',
untracked: false,
- paths: ['vendor/*']
+ paths: ['vendor/*'],
+ policy: 'pull-push'
}
}
end
diff --git a/spec/factories/ci/group_variables.rb b/spec/factories/ci/group_variables.rb
new file mode 100644
index 00000000000..565ced9eb1a
--- /dev/null
+++ b/spec/factories/ci/group_variables.rb
@@ -0,0 +1,12 @@
+FactoryGirl.define do
+ factory :ci_group_variable, class: Ci::GroupVariable do
+ sequence(:key) { |n| "VARIABLE_#{n}" }
+ value 'VARIABLE_VALUE'
+
+ trait(:protected) do
+ protected true
+ end
+
+ group factory: :group
+ end
+end
diff --git a/spec/factories/ci/pipeline_schedule_variables.rb b/spec/factories/ci/pipeline_schedule_variables.rb
new file mode 100644
index 00000000000..ca64d1aada0
--- /dev/null
+++ b/spec/factories/ci/pipeline_schedule_variables.rb
@@ -0,0 +1,8 @@
+FactoryGirl.define do
+ factory :ci_pipeline_schedule_variable, class: Ci::PipelineScheduleVariable do
+ sequence(:key) { |n| "VARIABLE_#{n}" }
+ value 'VARIABLE_VALUE'
+
+ pipeline_schedule factory: :ci_pipeline_schedule
+ end
+end
diff --git a/spec/factories/ci/pipeline_variable_variables.rb b/spec/factories/ci/pipeline_variable_variables.rb
new file mode 100644
index 00000000000..7c1a7faec08
--- /dev/null
+++ b/spec/factories/ci/pipeline_variable_variables.rb
@@ -0,0 +1,8 @@
+FactoryGirl.define do
+ factory :ci_pipeline_variable, class: Ci::PipelineVariable do
+ sequence(:key) { |n| "VARIABLE_#{n}" }
+ value 'VARIABLE_VALUE'
+
+ pipeline factory: :ci_empty_pipeline
+ end
+end
diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb
index 6712dd5d82e..33a17cf7ed5 100644
--- a/spec/factories/ci/runner_projects.rb
+++ b/spec/factories/ci/runner_projects.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :ci_runner_project, class: Ci::RunnerProject do
- runner_id 1
- project_id 1
+ runner factory: :ci_runner
+ project factory: :empty_project
end
end
diff --git a/spec/factories/ci/triggers.rb b/spec/factories/ci/triggers.rb
index c3a29d8bf04..40c4663c6d8 100644
--- a/spec/factories/ci/triggers.rb
+++ b/spec/factories/ci/triggers.rb
@@ -2,13 +2,6 @@ FactoryGirl.define do
factory :ci_trigger_without_token, class: Ci::Trigger do
factory :ci_trigger do
sequence(:token) { |n| "token#{n}" }
-
- factory :ci_trigger_for_trigger_schedule do
- token { SecureRandom.hex(15) }
- owner factory: :user
- project factory: :project
- ref 'master'
- end
end
end
end
diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb
index 36b9645438a..89e260cf65b 100644
--- a/spec/factories/commits.rb
+++ b/spec/factories/commits.rb
@@ -4,14 +4,19 @@ FactoryGirl.define do
factory :commit do
git_commit RepoHelpers.sample_commit
project factory: :empty_project
- author { build(:author) }
initialize_with do
new(git_commit, project)
end
+ after(:build) do |commit|
+ allow(commit).to receive(:author).and_return build(:author)
+ end
+
trait :without_author do
- author nil
+ after(:build) do |commit|
+ allow(commit).to receive(:author).and_return nil
+ end
end
end
end
diff --git a/spec/factories/gpg_keys.rb b/spec/factories/gpg_keys.rb
new file mode 100644
index 00000000000..1258dce8940
--- /dev/null
+++ b/spec/factories/gpg_keys.rb
@@ -0,0 +1,8 @@
+require_relative '../support/gpg_helpers'
+
+FactoryGirl.define do
+ factory :gpg_key do
+ key GpgHelpers::User1.public_key
+ user
+ end
+end
diff --git a/spec/factories/gpg_signature.rb b/spec/factories/gpg_signature.rb
new file mode 100644
index 00000000000..a5aeffbe12d
--- /dev/null
+++ b/spec/factories/gpg_signature.rb
@@ -0,0 +1,11 @@
+require_relative '../support/gpg_helpers'
+
+FactoryGirl.define do
+ factory :gpg_signature do
+ commit_sha { Digest::SHA1.hexdigest(SecureRandom.hex) }
+ project
+ gpg_key
+ gpg_key_primary_keyid { gpg_key.primary_keyid }
+ valid_signature true
+ end
+end
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index f1fd1fd7f73..a16695cb7c1 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -16,12 +16,8 @@ FactoryGirl.define do
state :closed
end
- trait :reopened do
- state :reopened
- end
-
factory :closed_issue, traits: [:closed]
- factory :reopened_issue, traits: [:reopened]
+ factory :reopened_issue, traits: [:opened]
factory :labeled_issue do
transient do
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 253a025af48..1bc530d06db 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -44,10 +44,6 @@ FactoryGirl.define do
state :opened
end
- trait :reopened do
- state :reopened
- end
-
trait :locked do
state :locked
end
@@ -74,7 +70,7 @@ FactoryGirl.define do
factory :merged_merge_request, traits: [:merged]
factory :closed_merge_request, traits: [:closed]
- factory :reopened_merge_request, traits: [:reopened]
+ factory :reopened_merge_request, traits: [:opened]
factory :merge_request_with_diffs, traits: [:with_diffs]
factory :merge_request_with_diff_notes do
after(:create) do |mr|
diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb
index 841ab3c73b8..b5e2ec60072 100644
--- a/spec/factories/milestones.rb
+++ b/spec/factories/milestones.rb
@@ -1,7 +1,13 @@
FactoryGirl.define do
factory :milestone do
title
- project factory: :empty_project
+
+ transient do
+ project nil
+ group nil
+ project_id nil
+ group_id nil
+ end
trait :active do
state "active"
@@ -11,6 +17,20 @@ FactoryGirl.define do
state "closed"
end
+ after(:build, :stub) do |milestone, evaluator|
+ if evaluator.group
+ milestone.group = evaluator.group
+ elsif evaluator.group_id
+ milestone.group_id = evaluator.group_id
+ elsif evaluator.project
+ milestone.project = evaluator.project
+ elsif evaluator.project_id
+ milestone.project_id = evaluator.project_id
+ else
+ milestone.project = create(:empty_project)
+ end
+ end
+
factory :active_milestone, traits: [:active]
factory :closed_milestone, traits: [:closed]
end
diff --git a/spec/factories/personal_snippets.rb b/spec/factories/personal_snippets.rb
deleted file mode 100644
index 0f13b2c1020..00000000000
--- a/spec/factories/personal_snippets.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-FactoryGirl.define do
- factory :personal_snippet, parent: :snippet, class: :PersonalSnippet do
- end
-end
diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb
index cd754ea235f..d754e980931 100644
--- a/spec/factories/project_hooks.rb
+++ b/spec/factories/project_hooks.rb
@@ -2,6 +2,7 @@ FactoryGirl.define do
factory :project_hook do
url { generate(:url) }
enable_ssl_verification false
+ project factory: :empty_project
trait :token do
token { SecureRandom.hex(10) }
diff --git a/spec/factories/project_snippets.rb b/spec/factories/project_snippets.rb
deleted file mode 100644
index e0fe1b36fd3..00000000000
--- a/spec/factories/project_snippets.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-FactoryGirl.define do
- factory :project_snippet, parent: :snippet, class: :ProjectSnippet do
- project factory: :empty_project
- end
-end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index aef1c17a239..485ed48d2de 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -171,10 +171,6 @@ FactoryGirl.define do
end
after :create do |project, evaluator|
- TestEnv.copy_repo(project,
- bare_repo: TestEnv.factory_repo_path_bare,
- refs: TestEnv::BRANCH_SHA)
-
if evaluator.create_template
args = evaluator.create_template
@@ -220,7 +216,7 @@ FactoryGirl.define do
active: true,
properties: {
'project_url' => 'http://redmine/projects/project_name_in_redmine',
- 'issues_url' => "http://redmine/#{project.id}/project_name_in_redmine/:id",
+ 'issues_url' => 'http://redmine/projects/project_name_in_redmine/issues/:id',
'new_issue_url' => 'http://redmine/projects/project_name_in_redmine/issues/new'
}
)
diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb
index b2695e0482a..3dbace4b38a 100644
--- a/spec/factories/protected_branches.rb
+++ b/spec/factories/protected_branches.rb
@@ -3,26 +3,58 @@ FactoryGirl.define do
name
project
- after(:build) do |protected_branch|
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
- protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER)
+ transient do
+ default_push_level true
+ default_merge_level true
+ default_access_level true
end
trait :developers_can_push do
- after(:create) do |protected_branch|
- protected_branch.push_access_levels.first.update!(access_level: Gitlab::Access::DEVELOPER)
+ transient do
+ default_push_level false
+ end
+
+ after(:build) do |protected_branch|
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end
end
trait :developers_can_merge do
- after(:create) do |protected_branch|
- protected_branch.merge_access_levels.first.update!(access_level: Gitlab::Access::DEVELOPER)
+ transient do
+ default_merge_level false
+ end
+
+ after(:build) do |protected_branch|
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end
end
trait :no_one_can_push do
- after(:create) do |protected_branch|
- protected_branch.push_access_levels.first.update!(access_level: Gitlab::Access::NO_ACCESS)
+ transient do
+ default_push_level false
+ end
+
+ after(:build) do |protected_branch|
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
+ end
+ end
+
+ trait :masters_can_push do
+ transient do
+ default_push_level false
+ end
+
+ after(:build) do |protected_branch|
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
+ end
+ end
+
+ after(:build) do |protected_branch, evaluator|
+ if evaluator.default_access_level && evaluator.default_push_level
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
+ end
+ if evaluator.default_access_level && evaluator.default_merge_level
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER)
end
end
end
diff --git a/spec/factories/protected_tags.rb b/spec/factories/protected_tags.rb
index d8e90ae1ee1..225588b23cc 100644
--- a/spec/factories/protected_tags.rb
+++ b/spec/factories/protected_tags.rb
@@ -3,19 +3,43 @@ FactoryGirl.define do
name
project
- after(:build) do |protected_tag|
- protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER)
+ transient do
+ default_access_level true
end
trait :developers_can_create do
- after(:create) do |protected_tag|
- protected_tag.create_access_levels.first.update!(access_level: Gitlab::Access::DEVELOPER)
+ transient do
+ default_access_level false
+ end
+
+ after(:build) do |protected_tag|
+ protected_tag.create_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end
end
trait :no_one_can_create do
- after(:create) do |protected_tag|
- protected_tag.create_access_levels.first.update!(access_level: Gitlab::Access::NO_ACCESS)
+ transient do
+ default_access_level false
+ end
+
+ after(:build) do |protected_tag|
+ protected_tag.create_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
+ end
+ end
+
+ trait :masters_can_create do
+ transient do
+ default_access_level false
+ end
+
+ after(:build) do |protected_tag|
+ protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER)
+ end
+ end
+
+ after(:build) do |protected_tag, evaluator|
+ if evaluator.default_access_level
+ protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER)
end
end
end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index e7366a7fd1c..30bc25cf88a 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -25,6 +25,14 @@ FactoryGirl.define do
})
end
+ factory :prometheus_service do
+ project factory: :empty_project
+ active true
+ properties({
+ api_url: 'https://prometheus.example.com/'
+ })
+ end
+
factory :jira_service do
project factory: :empty_project
active true
diff --git a/spec/factories/snippets.rb b/spec/factories/snippets.rb
index 388f662e6e5..f6ce99d50f9 100644
--- a/spec/factories/snippets.rb
+++ b/spec/factories/snippets.rb
@@ -18,4 +18,11 @@ FactoryGirl.define do
visibility_level Snippet::PRIVATE
end
end
+
+ factory :project_snippet, parent: :snippet, class: :ProjectSnippet do
+ project factory: :empty_project
+ end
+
+ factory :personal_snippet, parent: :snippet, class: :PersonalSnippet do
+ end
end
diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb
index 1383420fb44..3222c41c3d8 100644
--- a/spec/factories/uploads.rb
+++ b/spec/factories/uploads.rb
@@ -1,7 +1,7 @@
FactoryGirl.define do
factory :upload do
model { build(:project) }
- path { "uploads/system/project/avatar/avatar.jpg" }
+ path { "uploads/-/system/project/avatar/avatar.jpg" }
size 100.kilobytes
uploader "AvatarUploader"
end
diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb
index 5e6cd64c5c1..091fdcec3db 100644
--- a/spec/features/abuse_report_spec.rb
+++ b/spec/features/abuse_report_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Abuse reports', feature: true do
+feature 'Abuse reports' do
let(:another_user) { create(:user) }
before do
- gitlab_sign_in :user
+ sign_in(create(:user))
end
scenario 'Report abuse' do
@@ -12,7 +12,7 @@ feature 'Abuse reports', feature: true do
click_link 'Report abuse'
- fill_in 'abuse_report_message', with: 'This user send spam'
+ fill_in 'abuse_report_message', with: 'This user sends spam'
click_button 'Send report'
expect(page).to have_content 'Thank you for your report'
diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb
index 3a6e356b0b0..2144f6ba635 100644
--- a/spec/features/admin/admin_abuse_reports_spec.rb
+++ b/spec/features/admin/admin_abuse_reports_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe "Admin::AbuseReports", feature: true, js: true do
+describe "Admin::AbuseReports", js: true do
let(:user) { create(:user) }
context 'as an admin' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe 'if a user has been reported for abuse' do
diff --git a/spec/features/admin/admin_active_tab_spec.rb b/spec/features/admin/admin_active_tab_spec.rb
index c74336d8221..07430ecd6e0 100644
--- a/spec/features/admin/admin_active_tab_spec.rb
+++ b/spec/features/admin/admin_active_tab_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
RSpec.describe 'admin active tab' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
shared_examples 'page has active tab' do |title|
diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb
index d8fd4319328..5f3a37c1dcc 100644
--- a/spec/features/admin/admin_appearance_spec.rb
+++ b/spec/features/admin/admin_appearance_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Admin Appearance', feature: true do
+feature 'Admin Appearance' do
let!(:appearance) { create(:appearance) }
scenario 'Create new appearance' do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
visit admin_appearances_path
fill_in 'appearance_title', with: 'MyCompany'
@@ -20,7 +20,7 @@ feature 'Admin Appearance', feature: true do
end
scenario 'Preview appearance' do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
visit admin_appearances_path
click_link "Preview"
@@ -34,7 +34,7 @@ feature 'Admin Appearance', feature: true do
end
scenario 'Appearance logo' do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
visit admin_appearances_path
attach_file(:appearance_logo, logo_fixture)
@@ -46,7 +46,7 @@ feature 'Admin Appearance', feature: true do
end
scenario 'Header logos' do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
visit admin_appearances_path
attach_file(:appearance_header_logo, logo_fixture)
@@ -63,11 +63,11 @@ feature 'Admin Appearance', feature: true do
end
def logo_selector
- '//img[@src^="/uploads/system/appearance/logo"]'
+ '//img[data-src^="/uploads/-/system/appearance/logo"]'
end
def header_logo_selector
- '//img[@src^="/uploads/system/appearance/header_logo"]'
+ '//img[data-src^="/uploads/-/system/appearance/header_logo"]'
end
def logo_fixture
diff --git a/spec/features/admin/admin_broadcast_messages_spec.rb b/spec/features/admin/admin_broadcast_messages_spec.rb
index da063bf7b74..cbccf370514 100644
--- a/spec/features/admin/admin_broadcast_messages_spec.rb
+++ b/spec/features/admin/admin_broadcast_messages_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Admin Broadcast Messages', feature: true do
+feature 'Admin Broadcast Messages' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
create(:broadcast_message, :expired, message: 'Migration to new server')
visit admin_broadcast_messages_path
end
diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb
index d9c4fc686b1..31d4142a8e9 100644
--- a/spec/features/admin/admin_browse_spam_logs_spec.rb
+++ b/spec/features/admin/admin_browse_spam_logs_spec.rb
@@ -4,7 +4,7 @@ describe 'Admin browse spam logs' do
let!(:spam_log) { create(:spam_log, description: 'abcde ' * 20) }
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
scenario 'Browse spam logs' do
diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb
index c734a2ef16d..3e3404dfdac 100644
--- a/spec/features/admin/admin_browses_logs_spec.rb
+++ b/spec/features/admin/admin_browses_logs_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'Admin browses logs' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
it 'shows available log files' do
diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb
index e767081f3e5..e020579f71e 100644
--- a/spec/features/admin/admin_builds_spec.rb
+++ b/spec/features/admin/admin_builds_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'Admin Builds' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe 'GET /admin/builds' do
diff --git a/spec/features/admin/admin_cohorts_spec.rb b/spec/features/admin/admin_cohorts_spec.rb
index 952e5475213..bca52bf674c 100644
--- a/spec/features/admin/admin_cohorts_spec.rb
+++ b/spec/features/admin/admin_cohorts_spec.rb
@@ -1,8 +1,8 @@
require 'rails_helper'
-feature 'Admin cohorts page', feature: true do
+feature 'Admin cohorts page' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
scenario 'See users count per month' do
diff --git a/spec/features/admin/admin_conversational_development_index_spec.rb b/spec/features/admin/admin_conversational_development_index_spec.rb
index b484677a6df..2d2c7df5364 100644
--- a/spec/features/admin/admin_conversational_development_index_spec.rb
+++ b/spec/features/admin/admin_conversational_development_index_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'Admin Conversational Development Index' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
context 'when usage ping is disabled' do
diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb
index 81cddd03f80..241c7cbc34e 100644
--- a/spec/features/admin/admin_deploy_keys_spec.rb
+++ b/spec/features/admin/admin_deploy_keys_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-RSpec.describe 'admin deploy keys', type: :feature do
+RSpec.describe 'admin deploy keys' do
let!(:deploy_key) { create(:deploy_key, public: true) }
let!(:another_deploy_key) { create(:another_deploy_key, public: true) }
before do
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
end
it 'show all public deploy keys' do
diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
index 679bf63e0fd..931f4ec3d24 100644
--- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb
+++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'Admin disables Git access protocol', feature: true do
+feature 'Admin disables Git access protocol' do
include StubENV
let(:project) { create(:empty_project, :empty_repo) }
@@ -8,7 +8,7 @@ feature 'Admin disables Git access protocol', feature: true do
background do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- gitlab_sign_in(admin)
+ sign_in(admin)
end
context 'with HTTP disabled' do
@@ -51,7 +51,7 @@ feature 'Admin disables Git access protocol', feature: true do
end
def visit_project
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
def disable_http_protocol
diff --git a/spec/features/admin/admin_disables_two_factor_spec.rb b/spec/features/admin/admin_disables_two_factor_spec.rb
index 5437da29979..e214ae6b78d 100644
--- a/spec/features/admin/admin_disables_two_factor_spec.rb
+++ b/spec/features/admin/admin_disables_two_factor_spec.rb
@@ -1,8 +1,8 @@
require 'rails_helper'
-feature 'Admin disables 2FA for a user', feature: true do
+feature 'Admin disables 2FA for a user' do
scenario 'successfully', js: true do
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
user = create(:user, :two_factor)
edit_user(user)
@@ -17,7 +17,7 @@ feature 'Admin disables 2FA for a user', feature: true do
end
scenario 'for a user without 2FA enabled' do
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
user = create(:user)
edit_user(user)
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index 8b0fafc5f07..2e1bfcdcec3 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -1,14 +1,15 @@
require 'spec_helper'
-feature 'Admin Groups', feature: true do
+feature 'Admin Groups' do
include Select2Helper
let(:internal) { Gitlab::VisibilityLevel::INTERNAL }
let(:user) { create :user }
let!(:group) { create :group }
- let!(:current_user) { gitlab_sign_in :admin }
+ let!(:current_user) { create(:admin) }
before do
+ sign_in(current_user)
stub_application_setting(default_group_visibility: internal)
end
diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb
index 75093aa4167..106e7370a98 100644
--- a/spec/features/admin/admin_health_check_spec.rb
+++ b/spec/features/admin/admin_health_check_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature "Admin Health Check", feature: true do
+feature "Admin Health Check" do
include StubENV
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe '#show' do
diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb
index ec80c420c79..7910d5fb72b 100644
--- a/spec/features/admin/admin_hook_logs_spec.rb
+++ b/spec/features/admin/admin_hook_logs_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Admin::HookLogs', feature: true do
- let(:project) { create(:project) }
+feature 'Admin::HookLogs' do
+ let(:project) { create(:empty_project) }
let(:system_hook) { create(:system_hook) }
let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') }
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
scenario 'show list of hook logs' do
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index c07c21bd6a1..141109fd464 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe 'Admin::Hooks', feature: true do
+describe 'Admin::Hooks' do
before do
- @project = create(:project)
- gitlab_sign_in :admin
+ @project = create(:empty_project)
+ sign_in(create(:admin))
@system_hook = create(:system_hook)
end
@@ -74,11 +74,13 @@ describe 'Admin::Hooks', feature: true do
end
end
- describe 'Test' do
+ describe 'Test', js: true do
before do
WebMock.stub_request(:post, @system_hook.url)
visit admin_hooks_path
- click_link 'Test hook'
+
+ find('.hook-test-button.dropdown').click
+ click_link 'Push events'
end
it { expect(current_path).to eq(admin_hooks_path) }
diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb
index bb40918bd22..ae9b47299e6 100644
--- a/spec/features/admin/admin_labels_spec.rb
+++ b/spec/features/admin/admin_labels_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe 'admin issues labels' do
let!(:feature_label) { Label.create(title: 'feature', template: true) }
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe 'list' do
diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb
index ae41267e5fc..f979d2f6090 100644
--- a/spec/features/admin/admin_manage_applications_spec.rb
+++ b/spec/features/admin/admin_manage_applications_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-RSpec.describe 'admin manage applications', feature: true do
+RSpec.describe 'admin manage applications' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
it do
@@ -13,19 +13,24 @@ RSpec.describe 'admin manage applications', feature: true do
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
+ check :doorkeeper_application_trusted
click_on 'Submit'
expect(page).to have_content('Application: test')
expect(page).to have_content('Application Id')
expect(page).to have_content('Secret')
+ expect(page).to have_content('Trusted Y')
click_on 'Edit'
expect(page).to have_content('Edit application')
fill_in :doorkeeper_application_name, with: 'test_changed'
+ uncheck :doorkeeper_application_trusted
+
click_on 'Submit'
expect(page).to have_content('test_changed')
expect(page).to have_content('Application Id')
expect(page).to have_content('Secret')
+ expect(page).to have_content('Trusted N')
visit admin_applications_path
page.within '.oauth-applications' do
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index a4ce3e1d5ee..4f69eafcb9d 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -1,18 +1,21 @@
require 'spec_helper'
-describe "Admin::Projects", feature: true do
+describe "Admin::Projects" do
include Select2Helper
let(:user) { create :user }
- let!(:project) { create(:project) }
- let!(:current_user) do
- gitlab_sign_in :admin
+ let(:project) { create(:empty_project) }
+ let(:current_user) { create(:admin) }
+
+ before do
+ sign_in(current_user)
end
describe "GET /admin/projects" do
- let!(:archived_project) { create :project, :public, :archived }
+ let!(:archived_project) { create :empty_project, :public, :archived }
before do
+ expect(project).to be_persisted
visit admin_projects_path
end
@@ -37,15 +40,14 @@ describe "Admin::Projects", feature: true do
describe "GET /admin/projects/:namespace_id/:id" do
before do
- visit admin_projects_path
- click_link "#{project.name}"
- end
+ expect(project).to be_persisted
- it do
- expect(current_path).to eq admin_namespace_project_path(project.namespace, project)
+ visit admin_projects_path
+ click_link project.name
end
it "has project info" do
+ expect(current_path).to eq admin_project_path(project)
expect(page).to have_content(project.path)
expect(page).to have_content(project.name)
expect(page).to have_content(project.name_with_namespace)
@@ -54,6 +56,9 @@ describe "Admin::Projects", feature: true do
end
describe 'transfer project' do
+ # The gitlab-shell transfer will fail for a project without a repository
+ let(:project) { create(:project, :repository) }
+
before do
create(:group, name: 'Web')
@@ -62,7 +67,7 @@ describe "Admin::Projects", feature: true do
end
it 'transfers project to group web', js: true do
- visit admin_namespace_project_path(project.namespace, project)
+ visit admin_project_path(project)
click_button 'Search for Namespace'
click_link 'group: web'
@@ -79,7 +84,7 @@ describe "Admin::Projects", feature: true do
end
it 'adds admin a to a project as developer', js: true do
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
page.within '.users-project-form' do
select2(current_user.id, from: '#user_ids', multiple: true)
@@ -102,7 +107,7 @@ describe "Admin::Projects", feature: true do
end
it 'removes admin from the project' do
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
page.within '.content-list' do
expect(page).to have_content(current_user.name)
diff --git a/spec/features/admin/admin_requests_profiles_spec.rb b/spec/features/admin/admin_requests_profiles_spec.rb
index 2bfe401521b..380cd5d7703 100644
--- a/spec/features/admin/admin_requests_profiles_spec.rb
+++ b/spec/features/admin/admin_requests_profiles_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe 'Admin::RequestsProfilesController', feature: true do
+describe 'Admin::RequestsProfilesController' do
before do
FileUtils.mkdir_p(Gitlab::RequestProfiler::PROFILES_DIR)
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
end
after do
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 5b3323fed13..46bab3763cc 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -5,35 +5,58 @@ describe "Admin Runners" do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe "Runners page" do
- before do
- runner = FactoryGirl.create(:ci_runner, contacted_at: Time.now)
- pipeline = FactoryGirl.create(:ci_pipeline)
- FactoryGirl.create(:ci_build, pipeline: pipeline, runner_id: runner.id)
- visit admin_runners_path
- end
+ let(:pipeline) { create(:ci_pipeline) }
+
+ context "when there are runners" do
+ before do
+ runner = FactoryGirl.create(:ci_runner, contacted_at: Time.now)
+ FactoryGirl.create(:ci_build, pipeline: pipeline, runner_id: runner.id)
+ visit admin_runners_path
+ end
+
+ it 'has all necessary texts' do
+ expect(page).to have_text "How to setup"
+ expect(page).to have_text "Runners with last contact more than a minute ago: 1"
+ end
+
+ describe 'search' do
+ before do
+ FactoryGirl.create :ci_runner, description: 'runner-foo'
+ FactoryGirl.create :ci_runner, description: 'runner-bar'
+ end
+
+ it 'shows correct runner when description matches' do
+ search_form = find('#runners-search')
+ search_form.fill_in 'search', with: 'runner-foo'
+ search_form.click_button 'Search'
+
+ expect(page).to have_content("runner-foo")
+ expect(page).not_to have_content("runner-bar")
+ end
+
+ it 'shows no runner when description does not match' do
+ search_form = find('#runners-search')
+ search_form.fill_in 'search', with: 'runner-baz'
+ search_form.click_button 'Search'
- it 'has all necessary texts' do
- expect(page).to have_text "To register a new Runner"
- expect(page).to have_text "Runners with last contact more than a minute ago: 1"
+ expect(page).to have_text 'No runners found'
+ end
+ end
end
- describe 'search' do
+ context "when there are no runners" do
before do
- FactoryGirl.create :ci_runner, description: 'runner-foo'
- FactoryGirl.create :ci_runner, description: 'runner-bar'
-
- search_form = find('#runners-search')
- search_form.fill_in 'search', with: 'runner-foo'
- search_form.click_button 'Search'
+ visit admin_runners_path
end
- it 'shows correct runner' do
- expect(page).to have_content("runner-foo")
- expect(page).not_to have_content("runner-bar")
+ it 'has all necessary texts including no runner message' do
+ expect(page).to have_text "How to setup"
+ expect(page).to have_text "Runners with last contact more than a minute ago: 0"
+ expect(page).to have_text 'No runners found'
end
end
end
@@ -140,12 +163,11 @@ describe "Admin Runners" do
end
it 'has a registration token' do
- expect(page).to have_content("Registration token is #{token}")
- expect(page).to have_selector('#runners-token', text: token)
+ expect(page.find('#registration_token')).to have_content(token)
end
describe 'reload registration token' do
- let(:page_token) { find('#runners-token').text }
+ let(:page_token) { find('#registration_token').text }
before do
click_button 'Reset runners registration token'
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 2d6565e6d3b..c1eced417cf 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Admin updates settings', feature: true do
+feature 'Admin updates settings' do
include StubENV
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- gitlab_sign_in :admin
+ sign_in(create(:admin))
visit admin_application_settings_path
end
@@ -16,6 +16,19 @@ feature 'Admin updates settings', feature: true do
expect(page).to have_content "Application settings saved successfully"
end
+ scenario 'Uncheck all restricted visibility levels' do
+ find('#application_setting_visibility_level_0').set(false)
+ find('#application_setting_visibility_level_10').set(false)
+ find('#application_setting_visibility_level_20').set(false)
+
+ click_button 'Save'
+
+ expect(page).to have_content "Application settings saved successfully"
+ expect(find('#application_setting_visibility_level_0')).not_to be_checked
+ expect(find('#application_setting_visibility_level_10')).not_to be_checked
+ expect(find('#application_setting_visibility_level_20')).not_to be_checked
+ end
+
scenario 'Change application settings' do
uncheck 'Gravatar enabled'
fill_in 'Home page URL', with: 'https://about.gitlab.com/'
diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb
index 4efc7f0eb48..1fd1cda694a 100644
--- a/spec/features/admin/admin_system_info_spec.rb
+++ b/spec/features/admin/admin_system_info_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'Admin System Info' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe 'GET /admin/system_info' do
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 231c094c91d..034682dae27 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
+describe 'Admin > Users > Impersonation Tokens', js: true do
let(:admin) { create(:admin) }
let!(:user) { create(:user) }
@@ -8,12 +8,12 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
find(".table.active-tokens")
end
- def inactive_impersonation_tokens
- find(".table.inactive-tokens")
+ def no_personal_access_tokens_message
+ find(".settings-message")
end
before do
- gitlab_sign_in(admin)
+ sign_in(admin)
end
describe "token creation" do
@@ -32,11 +32,13 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
check "api"
check "read_user"
- expect { click_on "Create impersonation token" }.to change { PersonalAccessTokensFinder.new(impersonation: true).execute.count }
+ click_on "Create impersonation token"
+
expect(active_impersonation_tokens).to have_text(name)
expect(active_impersonation_tokens).to have_text('In')
expect(active_impersonation_tokens).to have_text('api')
expect(active_impersonation_tokens).to have_text('read_user')
+ expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1)
end
end
@@ -60,15 +62,17 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
click_on "Revoke"
- expect(inactive_impersonation_tokens).to have_text(impersonation_token.name)
+ expect(page).to have_selector(".settings-message")
+ expect(no_personal_access_tokens_message).to have_text("This user has no active Impersonation Tokens.")
end
- it "moves expired tokens to the 'inactive' section" do
+ it "removes expired tokens from 'active' section" do
impersonation_token.update(expires_at: 5.days.ago)
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(inactive_impersonation_tokens).to have_text(impersonation_token.name)
+ expect(page).to have_selector(".settings-message")
+ expect(no_personal_access_tokens_message).to have_text("This user has no active Impersonation Tokens.")
end
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 6dbc697642f..0dde8bb696c 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -1,11 +1,15 @@
require 'spec_helper'
-describe "Admin::Users", feature: true do
+describe "Admin::Users" do
let!(:user) do
create(:omniauth_user, provider: 'twitter', extern_uid: '123456')
end
- let!(:current_user) { gitlab_sign_in :admin }
+ let!(:current_user) { create(:admin) }
+
+ before do
+ sign_in(current_user)
+ end
describe "GET /admin/users" do
before do
@@ -253,7 +257,7 @@ describe "Admin::Users", feature: true do
describe "GET /admin/users/:id/projects" do
let(:group) { create(:group) }
- let!(:project) { create(:project, group: group) }
+ let!(:project) { create(:empty_project, group: group) }
before do
group.add_developer(user)
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
index 91d70435db8..5b3ee6ee822 100644
--- a/spec/features/admin/admin_uses_repository_checks_spec.rb
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'Admin uses repository checks', feature: true do
+feature 'Admin uses repository checks' do
include StubENV
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
scenario 'to trigger a single check' do
@@ -43,6 +43,6 @@ feature 'Admin uses repository checks', feature: true do
end
def visit_admin_project_page(project)
- visit admin_namespace_project_path(project.namespace, project)
+ visit admin_project_path(project)
end
end
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index 711c8a710f3..d70da7f09e9 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe "Dashboard Issues Feed", feature: true do
+describe "Dashboard Issues Feed" do
describe "GET /issues" do
let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
- let!(:project1) { create(:project) }
- let!(:project2) { create(:project) }
+ let!(:project1) { create(:empty_project) }
+ let!(:project2) { create(:empty_project) }
before do
project1.team << [user, :master]
diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb
index 2f4bb45d74b..a7c12853981 100644
--- a/spec/features/atom/dashboard_spec.rb
+++ b/spec/features/atom/dashboard_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Dashboard Feed", feature: true do
+describe "Dashboard Feed" do
describe "GET /" do
let!(:user) { create(:user, name: "Jonh") }
@@ -19,7 +19,7 @@ describe "Dashboard Feed", feature: true do
end
context 'feed content' do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project, author: user, description: '') }
let(:note) { create(:note, noteable: issue, author: user, note: 'Bug confirmed', project: project) }
diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb
index b94ad973fed..59e20d7e24d 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/features/atom/issues_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe 'Issues Feed', feature: true do
+describe 'Issues Feed' do
describe 'GET /issues' do
let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
let!(:group) { create(:group) }
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:issue) { create(:issue, author: user, assignees: [assignee], project: project) }
before do
@@ -15,8 +15,8 @@ describe 'Issues Feed', feature: true do
context 'when authenticated' do
it 'renders atom feed' do
- gitlab_sign_in user
- visit namespace_project_issues_path(project.namespace, project, :atom)
+ sign_in user
+ visit project_issues_path(project, :atom)
expect(response_headers['Content-Type'])
.to have_content('application/atom+xml')
@@ -30,7 +30,7 @@ describe 'Issues Feed', feature: true do
context 'when authenticated via private token' do
it 'renders atom feed' do
- visit namespace_project_issues_path(project.namespace, project, :atom,
+ visit project_issues_path(project, :atom,
private_token: user.private_token)
expect(response_headers['Content-Type'])
@@ -45,7 +45,7 @@ describe 'Issues Feed', feature: true do
context 'when authenticated via RSS token' do
it 'renders atom feed' do
- visit namespace_project_issues_path(project.namespace, project, :atom,
+ visit project_issues_path(project, :atom,
rss_token: user.rss_token)
expect(response_headers['Content-Type'])
@@ -59,7 +59,7 @@ describe 'Issues Feed', feature: true do
end
it "renders atom feed with url parameters for project issues" do
- visit namespace_project_issues_path(project.namespace, project,
+ visit project_issues_path(project,
:atom, rss_token: user.rss_token, state: 'opened', assignee_id: user.id)
link = find('link[type="application/atom+xml"]')
diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb
index 44ae7204bcf..79069bbca8e 100644
--- a/spec/features/atom/users_spec.rb
+++ b/spec/features/atom/users_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "User Feed", feature: true do
+describe "User Feed" do
describe "GET /" do
let!(:user) { create(:user) }
@@ -19,7 +19,7 @@ describe "User Feed", feature: true do
end
context 'feed content' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:issue) do
create(:issue,
project: project,
diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb
index 74f5f70702a..dff6f96b663 100644
--- a/spec/features/auto_deploy_spec.rb
+++ b/spec/features/auto_deploy_spec.rb
@@ -7,7 +7,7 @@ describe 'Auto deploy' do
before do
create :kubernetes_service, project: project
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'when no deployment service is active' do
@@ -16,7 +16,7 @@ describe 'Auto deploy' do
end
it 'does not show a button to set up auto deploy' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_no_content('Set up auto deploy')
end
end
@@ -24,7 +24,7 @@ describe 'Auto deploy' do
context 'when a deployment service is active' do
before do
project.kubernetes_service.update!(active: true)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
it 'shows a button to set up auto deploy' do
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index ba58af22841..c87469696da 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Issue Boards add issue modal', :feature, :js do
+describe 'Issue Boards add issue modal', :js do
let(:project) { create(:empty_project, :public) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
@@ -14,14 +14,14 @@ describe 'Issue Boards add issue modal', :feature, :js do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
end
it 'resets filtered search state' do
- visit namespace_project_board_path(project.namespace, project, board, search: 'testing')
+ visit project_board_path(project, board, search: 'testing')
wait_for_requests
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 87fc31d414c..c3711c9b2c5 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -1,9 +1,10 @@
require 'rails_helper'
-describe 'Issue Boards', feature: true, js: true do
+describe 'Issue Boards', js: true do
include DragTo
- let(:project) { create(:empty_project, :public) }
+ let(:group) { create(:group, :nested) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
let!(:user2) { create(:user) }
@@ -12,12 +13,12 @@ describe 'Issue Boards', feature: true, js: true do
project.team << [user, :master]
project.team << [user2, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'no lists' do
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 3)
end
@@ -81,7 +82,7 @@ describe 'Issue Boards', feature: true, js: true do
let!(:issue9) { create(:labeled_issue, project: project, labels: [planning, testing, bug, accepting], relative_position: 1) }
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
@@ -158,7 +159,7 @@ describe 'Issue Boards', feature: true, js: true do
create(:labeled_issue, project: project, labels: [planning])
end
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
page.within(find('.board:nth-child(2)')) do
@@ -507,7 +508,7 @@ describe 'Issue Boards', feature: true, js: true do
context 'keyboard shortcuts' do
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
end
@@ -519,8 +520,8 @@ describe 'Issue Boards', feature: true, js: true do
context 'signed out user' do
before do
- gitlab_sign_out
- visit namespace_project_board_path(project.namespace, project, board)
+ sign_out(:user)
+ visit project_board_path(project, board)
wait_for_requests
end
@@ -542,9 +543,9 @@ describe 'Issue Boards', feature: true, js: true do
before do
project.team << [user_guest, :guest]
- gitlab_sign_out
- gitlab_sign_in(user_guest)
- visit namespace_project_board_path(project.namespace, project, board)
+ sign_out(:user)
+ sign_in(user_guest)
+ visit project_board_path(project, board)
wait_for_requests
end
diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb
index 1e620061e5e..f4be56a4463 100644
--- a/spec/features/boards/issue_ordering_spec.rb
+++ b/spec/features/boards/issue_ordering_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Issue Boards', :feature, :js do
+describe 'Issue Boards', :js do
include DragTo
let(:project) { create(:empty_project, :public) }
@@ -15,14 +15,14 @@ describe 'Issue Boards', :feature, :js do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'un-ordered issues' do
let!(:issue4) { create(:labeled_issue, project: project, labels: [label]) }
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 3)
@@ -47,7 +47,7 @@ describe 'Issue Boards', :feature, :js do
context 'ordering in list' do
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 3)
@@ -110,7 +110,7 @@ describe 'Issue Boards', :feature, :js do
let!(:issue6) { create(:labeled_issue, project: project, title: 'testing 3', labels: [label2], relative_position: 1.0) }
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 4)
diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb
index ed3b38e6a7e..415eda0e058 100644
--- a/spec/features/boards/keyboard_shortcut_spec.rb
+++ b/spec/features/boards/keyboard_shortcut_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-describe 'Issue Boards shortcut', feature: true, js: true do
+describe 'Issue Boards shortcut', js: true do
let(:project) { create(:empty_project) }
before do
create(:board, project: project)
- gitlab_sign_in :admin
+ sign_in(create(:admin))
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
it 'takes user to issue board index' do
diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb
index 8899e1ef5e5..1c8b9c46569 100644
--- a/spec/features/boards/modal_filter_spec.rb
+++ b/spec/features/boards/modal_filter_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Issue Boards add issue modal filtering', :feature, :js do
+describe 'Issue Boards add issue modal filtering', :js do
let(:project) { create(:empty_project, :public) }
let(:board) { create(:board, project: project) }
let(:planning) { create(:label, project: project, name: 'Planning') }
@@ -12,7 +12,7 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'shows empty state when no results found' do
@@ -202,7 +202,7 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
end
def visit_board
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
click_button('Add issues')
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index 77cd87d6601..1dbe3dbda11 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Issue Boards new issue', feature: true, js: true do
+describe 'Issue Boards new issue', js: true do
let(:project) { create(:empty_project, :public) }
let(:board) { create(:board, project: project) }
let!(:list) { create(:list, board: board, position: 0) }
@@ -10,9 +10,9 @@ describe 'Issue Boards new issue', feature: true, js: true do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
expect(page).to have_selector('.board', count: 3)
@@ -83,7 +83,7 @@ describe 'Issue Boards new issue', feature: true, js: true do
context 'unauthorized user' do
before do
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
end
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index fd0776041ed..9b3fb48046a 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Issue Boards', feature: true, js: true do
+describe 'Issue Boards', js: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:project) { create(:empty_project, :public) }
@@ -20,9 +20,9 @@ describe 'Issue Boards', feature: true, js: true do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
end
@@ -79,6 +79,22 @@ describe 'Issue Boards', feature: true, js: true do
end
end
+ it 'does not show remove button for backlog or closed issues' do
+ create(:issue, project: project)
+ create(:issue, :closed, project: project)
+
+ visit project_board_path(project, board)
+ wait_for_requests
+
+ click_card(find('.board:nth-child(1)').first('.card'))
+
+ expect(find('.issue-boards-sidebar')).not_to have_button 'Remove from board'
+
+ click_card(find('.board:nth-child(3)').first('.card'))
+
+ expect(find('.issue-boards-sidebar')).not_to have_button 'Remove from board'
+ end
+
context 'assignee' do
it 'updates the issues assignee' do
click_card(card)
diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb
index d57ae6a71e7..f54f2234203 100644
--- a/spec/features/boards/sub_group_project_spec.rb
+++ b/spec/features/boards/sub_group_project_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Sub-group project issue boards', :feature, :js do
+describe 'Sub-group project issue boards', :js do
let(:group) { create(:group) }
let(:nested_group_1) { create(:group, parent: group) }
let(:project) { create(:empty_project, group: nested_group_1) }
@@ -13,9 +13,9 @@ describe 'Sub-group project issue boards', :feature, :js do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_board_path(project.namespace, project, board)
+ visit project_board_path(project, board)
wait_for_requests
end
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index b2e72fc7dee..1e7fd7b62bd 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Contributions Calendar', :feature, :js do
+feature 'Contributions Calendar', :js do
let(:user) { create(:user) }
let(:contributed_project) { create(:empty_project, :public) }
let(:issue_note) { create(:note, project: contributed_project) }
@@ -68,7 +68,7 @@ feature 'Contributions Calendar', :feature, :js do
end
before do
- gitlab_sign_in user
+ sign_in user
end
describe 'calendar day selection' do
diff --git a/spec/features/ci_lint_spec.rb b/spec/features/ci_lint_spec.rb
index de16ee3e567..af4cc00162a 100644
--- a/spec/features/ci_lint_spec.rb
+++ b/spec/features/ci_lint_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'CI Lint', js: true do
before do
- gitlab_sign_in :user
+ sign_in(create(:user))
end
describe 'YAML parsing' do
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 0373f649ee8..15ec6f20763 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -66,7 +66,7 @@ describe 'Commits' do
end
before do
- visit namespace_project_commits_path(project.namespace, project, :master)
+ visit project_commits_path(project, :master)
end
it 'shows correct build status from default branch' do
@@ -77,7 +77,7 @@ describe 'Commits' do
end
end
- describe 'Commit builds', :feature, :js do
+ describe 'Commit builds', :js do
before do
visit ci_status_path(pipeline)
end
@@ -152,7 +152,7 @@ describe 'Commits' do
visit ci_status_path(pipeline)
end
- it 'Renders header', :feature, :js do
+ it 'Renders header', :js do
expect(page).to have_content pipeline.sha[0..7]
expect(page).to have_content pipeline.git_commit_message
expect(page).to have_content pipeline.user.name
@@ -165,7 +165,7 @@ describe 'Commits' do
end
end
- context 'when accessing internal project with disallowed access', :feature, :js do
+ context 'when accessing internal project with disallowed access', :js do
before do
project.update(
visibility_level: Gitlab::VisibilityLevel::INTERNAL,
@@ -192,7 +192,7 @@ describe 'Commits' do
before do
project.team << [user, :master]
sign_in(user)
- visit namespace_project_commits_path(project.namespace, project, branch_name)
+ visit project_commits_path(project, branch_name)
end
it 'includes the committed_date for each commit' do
@@ -203,4 +203,105 @@ describe 'Commits' do
end
end
end
+
+ describe 'GPG signed commits', :js do
+ it 'changes from unverified to verified when the user changes his email to match the gpg key' do
+ user = create :user, email: 'unrelated.user@example.org'
+ project.team << [user, :master]
+
+ Sidekiq::Testing.inline! do
+ create :gpg_key, key: GpgHelpers::User1.public_key, user: user
+ end
+
+ sign_in(user)
+
+ visit project_commits_path(project, :'signed-commits')
+
+ within '#commits-list' do
+ expect(page).to have_content 'Unverified'
+ expect(page).not_to have_content 'Verified'
+ end
+
+ # user changes his email which makes the gpg key verified
+ Sidekiq::Testing.inline! do
+ user.skip_reconfirmation!
+ user.update_attributes!(email: GpgHelpers::User1.emails.first)
+ end
+
+ visit project_commits_path(project, :'signed-commits')
+
+ within '#commits-list' do
+ expect(page).to have_content 'Unverified'
+ expect(page).to have_content 'Verified'
+ end
+ end
+
+ it 'changes from unverified to verified when the user adds the missing gpg key' do
+ user = create :user, email: GpgHelpers::User1.emails.first
+ project.team << [user, :master]
+
+ sign_in(user)
+
+ visit project_commits_path(project, :'signed-commits')
+
+ within '#commits-list' do
+ expect(page).to have_content 'Unverified'
+ expect(page).not_to have_content 'Verified'
+ end
+
+ # user adds the gpg key which makes the signature valid
+ Sidekiq::Testing.inline! do
+ create :gpg_key, key: GpgHelpers::User1.public_key, user: user
+ end
+
+ visit project_commits_path(project, :'signed-commits')
+
+ within '#commits-list' do
+ expect(page).to have_content 'Unverified'
+ expect(page).to have_content 'Verified'
+ end
+ end
+
+ it 'shows popover badges' do
+ gpg_user = create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard'
+ Sidekiq::Testing.inline! do
+ create :gpg_key, key: GpgHelpers::User1.public_key, user: gpg_user
+ end
+
+ user = create :user
+ project.team << [user, :master]
+
+ sign_in(user)
+ visit project_commits_path(project, :'signed-commits')
+
+ # unverified signature
+ click_on 'Unverified', match: :first
+ within '.popover' do
+ expect(page).to have_content 'This commit was signed with an unverified signature.'
+ expect(page).to have_content "GPG Key ID: #{GpgHelpers::User2.primary_keyid}"
+ end
+
+ # verified and the gpg user has a gitlab profile
+ click_on 'Verified'
+ within '.popover' do
+ expect(page).to have_content 'This commit was signed with a verified signature.'
+ expect(page).to have_content 'Nannie Bernhard'
+ expect(page).to have_content '@nannie.bernhard'
+ expect(page).to have_content "GPG Key ID: #{GpgHelpers::User1.primary_keyid}"
+ end
+
+ # verified and the gpg user's profile doesn't exist anymore
+ gpg_user.destroy!
+
+ visit project_commits_path(project, :'signed-commits')
+
+ click_on 'Verified'
+ within '.popover' do
+ expect(page).to have_content 'This commit was signed with a verified signature.'
+ expect(page).to have_content 'Nannie Bernhard'
+ expect(page).to have_content 'nannie.bernhard@example.com'
+ expect(page).to have_content "GPG Key ID: #{GpgHelpers::User1.primary_keyid}"
+ end
+ end
+ end
end
diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb
index 80d16539d5a..8f59ce3d2e7 100644
--- a/spec/features/container_registry_spec.rb
+++ b/spec/features/container_registry_spec.rb
@@ -9,7 +9,7 @@ describe "Container Registry" do
end
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.add_developer(user)
stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any, tags: [])
@@ -55,7 +55,6 @@ describe "Container Registry" do
end
def visit_container_registry
- visit namespace_project_container_registry_index_path(
- project.namespace, project)
+ visit project_container_registry_index_path(project)
end
end
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
index 005c88f6bab..3e6a27eafd8 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe 'Copy as GFM', feature: true, js: true do
+describe 'Copy as GFM', js: true do
include MarkupHelper
include RepoHelpers
include ActionView::Helpers::JavaScriptHelper
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe 'Copying rendered GFM' do
@@ -16,7 +16,7 @@ describe 'Copy as GFM', feature: true, js: true do
# `markdown` helper expects a `@project` variable
@project = @feat.project
- visit namespace_project_issue_path(@project.namespace, @project, @feat.issue)
+ visit project_issue_path(@project, @feat.issue)
end
# The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert GitLab Flavored Markdown (GFM) to HTML.
@@ -121,13 +121,13 @@ describe 'Copy as GFM', feature: true, js: true do
# full issue reference
@feat.issue.to_reference(full: true),
# issue URL
- namespace_project_issue_url(@project.namespace, @project, @feat.issue),
+ project_issue_url(@project, @feat.issue),
# issue URL with note anchor
- namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123'),
+ project_issue_url(@project, @feat.issue, anchor: 'note_123'),
# issue link
- "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue)})",
+ "[Issue](#{project_issue_url(@project, @feat.issue)})",
# issue link with note anchor
- "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123')})"
+ "[Issue](#{project_issue_url(@project, @feat.issue, anchor: 'note_123')})"
)
verify(
@@ -466,7 +466,7 @@ describe 'Copy as GFM', feature: true, js: true do
context 'from a diff' do
before do
- visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
+ visit project_commit_path(project, sample_commit.id)
end
context 'selecting one word of text' do
@@ -507,7 +507,7 @@ describe 'Copy as GFM', feature: true, js: true do
context 'from a blob' do
before do
- visit namespace_project_blob_path(project.namespace, project, File.join('master', 'files/ruby/popen.rb'))
+ visit project_blob_path(project, File.join('master', 'files/ruby/popen.rb'))
wait_for_requests
end
@@ -549,7 +549,7 @@ describe 'Copy as GFM', feature: true, js: true do
context 'from a GFM code block' do
before do
- visit namespace_project_blob_path(project.namespace, project, File.join('markdown', 'doc/api/users.md'))
+ visit project_blob_path(project, File.join('markdown', 'doc/api/users.md'))
wait_for_requests
end
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 5a7ea975455..5c60cca10b9 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Cycle Analytics', feature: true, js: true do
+feature 'Cycle Analytics', js: true do
let(:user) { create(:user) }
let(:guest) { create(:user) }
let(:project) { create(:project, :repository) }
@@ -14,9 +14,9 @@ feature 'Cycle Analytics', feature: true, js: true do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_cycle_analytics_path(project.namespace, project)
+ visit project_cycle_analytics_path(project)
wait_for_requests
end
@@ -38,8 +38,8 @@ feature 'Cycle Analytics', feature: true, js: true do
create_cycle
deploy_master
- gitlab_sign_in(user)
- visit namespace_project_cycle_analytics_path(project.namespace, project)
+ sign_in(user)
+ visit project_cycle_analytics_path(project)
end
it 'shows data on each stage' do
@@ -70,8 +70,8 @@ feature 'Cycle Analytics', feature: true, js: true do
user.update_attribute(:preferred_language, 'es')
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_cycle_analytics_path(project.namespace, project)
+ sign_in(user)
+ visit project_cycle_analytics_path(project)
wait_for_requests
end
@@ -93,8 +93,8 @@ feature 'Cycle Analytics', feature: true, js: true do
create_cycle
deploy_master
- gitlab_sign_in(guest)
- visit namespace_project_cycle_analytics_path(project.namespace, project)
+ sign_in(guest)
+ visit project_cycle_analytics_path(project)
wait_for_requests
end
diff --git a/spec/features/dashboard/active_tab_spec.rb b/spec/features/dashboard/active_tab_spec.rb
index f32f23faebc..ee2554cbd48 100644
--- a/spec/features/dashboard/active_tab_spec.rb
+++ b/spec/features/dashboard/active_tab_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Active Tab', js: true, feature: true do
+RSpec.describe 'Dashboard Active Tab', js: true do
before do
- gitlab_sign_in :user
+ sign_in(create(:user))
end
shared_examples 'page has active tab' do |title|
diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb
index 1e9cabe7850..a96270c9147 100644
--- a/spec/features/dashboard/activity_spec.rb
+++ b/spec/features/dashboard/activity_spec.rb
@@ -1,11 +1,162 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Activity', feature: true do
+feature 'Dashboard > Activity' do
+ let(:user) { create(:user) }
+
before do
- gitlab_sign_in(create :user)
- visit activity_dashboard_path
+ sign_in(user)
+ end
+
+ context 'rss' do
+ before do
+ visit activity_dashboard_path
+ end
+
+ it_behaves_like "it has an RSS button with current_user's RSS token"
+ it_behaves_like "an autodiscoverable RSS feed with current_user's RSS token"
end
- it_behaves_like "it has an RSS button with current_user's RSS token"
- it_behaves_like "an autodiscoverable RSS feed with current_user's RSS token"
+ context 'event filters', :js do
+ let(:project) { create(:empty_project) }
+
+ let(:merge_request) do
+ create(:merge_request, author: user, source_project: project, target_project: project)
+ end
+
+ let(:push_event_data) do
+ {
+ before: Gitlab::Git::BLANK_SHA,
+ after: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e',
+ ref: 'refs/heads/new_design',
+ user_id: user.id,
+ user_name: user.name,
+ repository: {
+ name: project.name,
+ url: 'localhost/rubinius',
+ description: '',
+ homepage: 'localhost/rubinius',
+ private: true
+ }
+ }
+ end
+
+ let(:note) { create(:note, project: project, noteable: merge_request) }
+
+ let!(:push_event) do
+ create(:event, :pushed, data: push_event_data, project: project, author: user)
+ end
+
+ let!(:merged_event) do
+ create(:event, :merged, project: project, target: merge_request, author: user)
+ end
+
+ let!(:joined_event) do
+ create(:event, :joined, project: project, author: user)
+ end
+
+ let!(:closed_event) do
+ create(:event, :closed, project: project, target: merge_request, author: user)
+ end
+
+ let!(:comments_event) do
+ create(:event, :commented, project: project, target: note, author: user)
+ end
+
+ before do
+ project.add_master(user)
+
+ visit activity_dashboard_path
+ wait_for_requests
+ end
+
+ scenario 'user should see all events' do
+ within '.content_list' do
+ expect(page).to have_content('pushed new branch')
+ expect(page).to have_content('joined')
+ expect(page).to have_content('accepted')
+ expect(page).to have_content('closed')
+ expect(page).to have_content('commented on')
+ end
+ end
+
+ scenario 'user should see only pushed events' do
+ click_link('Push events')
+ wait_for_requests
+
+ within '.content_list' do
+ expect(page).to have_content('pushed new branch')
+ expect(page).not_to have_content('joined')
+ expect(page).not_to have_content('accepted')
+ expect(page).not_to have_content('closed')
+ expect(page).not_to have_content('commented on')
+ end
+ end
+
+ scenario 'user should see only merged events' do
+ click_link('Merge events')
+ wait_for_requests
+
+ within '.content_list' do
+ expect(page).not_to have_content('pushed new branch')
+ expect(page).not_to have_content('joined')
+ expect(page).to have_content('accepted')
+ expect(page).not_to have_content('closed')
+ expect(page).not_to have_content('commented on')
+ end
+ end
+
+ scenario 'user should see only issues events' do
+ click_link('Issue events')
+ wait_for_requests
+
+ within '.content_list' do
+ expect(page).not_to have_content('pushed new branch')
+ expect(page).not_to have_content('joined')
+ expect(page).not_to have_content('accepted')
+ expect(page).to have_content('closed')
+ expect(page).not_to have_content('commented on')
+ end
+ end
+
+ scenario 'user should see only comments events' do
+ click_link('Comments')
+ wait_for_requests
+
+ within '.content_list' do
+ expect(page).not_to have_content('pushed new branch')
+ expect(page).not_to have_content('joined')
+ expect(page).not_to have_content('accepted')
+ expect(page).not_to have_content('closed')
+ expect(page).to have_content('commented on')
+ end
+ end
+
+ scenario 'user should see only joined events' do
+ click_link('Team')
+ wait_for_requests
+
+ within '.content_list' do
+ expect(page).not_to have_content('pushed new branch')
+ expect(page).to have_content('joined')
+ expect(page).not_to have_content('accepted')
+ expect(page).not_to have_content('closed')
+ expect(page).not_to have_content('commented on')
+ end
+ end
+
+ scenario 'user see selected event after page reloading' do
+ click_link('Push events')
+ wait_for_requests
+ visit activity_dashboard_path
+ wait_for_requests
+
+ within '.content_list' do
+ expect(page).to have_content('pushed new branch')
+ expect(page).not_to have_content('joined')
+ expect(page).not_to have_content('accepted')
+ expect(page).not_to have_content('closed')
+ expect(page).not_to have_content('commented on')
+ end
+ end
+ end
end
diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb
index a5ba3e7e3cf..ceac6a0a27c 100644
--- a/spec/features/dashboard/archived_projects_spec.rb
+++ b/spec/features/dashboard/archived_projects_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Archived Project', feature: true do
+RSpec.describe 'Dashboard Archived Project' do
let(:user) { create :user }
let(:project) { create :project}
- let(:archived_project) { create(:project, :archived) }
+ let(:archived_project) { create(:empty_project, :archived) }
before do
project.team << [user, :master]
archived_project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_projects_path
end
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index 6931d0a840e..05dcdd93f37 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Tooltips on .timeago dates', feature: true, js: true do
+feature 'Tooltips on .timeago dates', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+ let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
let(:created_date) { Date.yesterday.to_time }
let(:expected_format) { created_date.in_time_zone.strftime('%b %-d, %Y %l:%M%P') }
@@ -13,7 +13,7 @@ feature 'Tooltips on .timeago dates', feature: true, js: true do
Event.create( project: project, author_id: user.id, action: Event::JOINED,
updated_at: created_date, created_at: created_date)
- gitlab_sign_in user
+ sign_in user
visit user_path(user)
wait_for_requests()
@@ -30,7 +30,7 @@ feature 'Tooltips on .timeago dates', feature: true, js: true do
project.team << [user, :master]
create(:snippet, author: user, updated_at: created_date, created_at: created_date)
- gitlab_sign_in user
+ sign_in user
visit user_snippets_path(user)
wait_for_requests()
diff --git a/spec/features/dashboard/group_spec.rb b/spec/features/dashboard/group_spec.rb
index 6c8958cb376..1c4699c3818 100644
--- a/spec/features/dashboard/group_spec.rb
+++ b/spec/features/dashboard/group_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Group', feature: true do
+RSpec.describe 'Dashboard Group' do
before do
- gitlab_sign_in(:user)
+ sign_in(create(:user))
end
it 'creates new group', js: true do
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index 1ecc27a0cca..bb4f3d9ecb4 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Dashboard Groups page', js: true, feature: true do
+feature 'Dashboard Groups page', :js do
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:nested_group) { create(:group, :nested) }
@@ -10,7 +10,7 @@ describe 'Dashboard Groups page', js: true, feature: true do
group.add_owner(user)
nested_group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_groups_path
expect(page).to have_content(group.full_name)
@@ -23,7 +23,7 @@ describe 'Dashboard Groups page', js: true, feature: true do
group.add_owner(user)
nested_group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_groups_path
end
@@ -41,7 +41,7 @@ describe 'Dashboard Groups page', js: true, feature: true do
fill_in 'filter_groups', with: group.name
wait_for_requests
- fill_in 'filter_groups', with: ""
+ fill_in 'filter_groups', with: ''
wait_for_requests
expect(page).to have_content(group.full_name)
@@ -58,7 +58,7 @@ describe 'Dashboard Groups page', js: true, feature: true do
group.add_owner(user)
subgroup.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_groups_path
end
@@ -98,7 +98,7 @@ describe 'Dashboard Groups page', js: true, feature: true do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_groups_path
end
diff --git a/spec/features/dashboard/help_spec.rb b/spec/features/dashboard/help_spec.rb
index 25b0f40c9cd..68bfbf22736 100644
--- a/spec/features/dashboard/help_spec.rb
+++ b/spec/features/dashboard/help_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Help', feature: true do
+RSpec.describe 'Dashboard Help' do
before do
- gitlab_sign_in(:user)
+ sign_in(create(:user))
end
it 'renders correctly markdown' do
diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb
index 8a8a20fd5b1..ae68b0f65d5 100644
--- a/spec/features/dashboard/issuables_counter_spec.rb
+++ b/spec/features/dashboard/issuables_counter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Navigation bar counter', feature: true, caching: true do
+describe 'Navigation bar counter', :use_clean_rails_memory_store_caching do
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace) }
let(:issue) { create(:issue, project: project) }
@@ -9,7 +9,7 @@ describe 'Navigation bar counter', feature: true, caching: true do
before do
issue.assignees = [user]
merge_request.update(assignee: user)
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'reflects dashboard issues count' do
diff --git a/spec/features/dashboard_issues_spec.rb b/spec/features/dashboard/issues_filter_spec.rb
index c4dbaad2895..0ce642f32f2 100644
--- a/spec/features/dashboard_issues_spec.rb
+++ b/spec/features/dashboard/issues_filter_spec.rb
@@ -1,21 +1,23 @@
require 'spec_helper'
-describe "Dashboard Issues filtering", feature: true, js: true do
+feature 'Dashboard Issues filtering', :js do
+ include SortingHelper
+
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:milestone) { create(:milestone, project: project) }
- context 'filtering by milestone' do
- before do
- project.team << [user, :master]
- gitlab_sign_in(user)
+ let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
+ let!(:issue2) { create(:issue, project: project, author: user, assignees: [user], milestone: milestone) }
- create(:issue, project: project, author: user, assignees: [user])
- create(:issue, project: project, author: user, assignees: [user], milestone: milestone)
+ before do
+ project.add_master(user)
+ sign_in(user)
- visit_issues
- end
+ visit_issues
+ end
+ context 'filtering by milestone' do
it 'shows all issues with no milestone' do
show_milestone_dropdown
@@ -62,6 +64,46 @@ describe "Dashboard Issues filtering", feature: true, js: true do
end
end
+ context 'filtering by label' do
+ let(:label) { create(:label, project: project) }
+ let!(:label_link) { create(:label_link, label: label, target: issue) }
+
+ it 'shows all issues without filter' do
+ page.within 'ul.content-list' do
+ expect(page).to have_content issue.title
+ expect(page).to have_content issue2.title
+ end
+ end
+
+ it 'shows all issues with the selected label' do
+ page.within '.labels-filter' do
+ find('.dropdown').click
+ click_link label.title
+ end
+
+ page.within 'ul.content-list' do
+ expect(page).to have_content issue.title
+ expect(page).not_to have_content issue2.title
+ end
+ end
+ end
+
+ context 'sorting' do
+ it 'shows sorted issues' do
+ sorting_by('Oldest updated')
+ visit_issues
+
+ expect(find('.issues-filters')).to have_content('Oldest updated')
+ end
+
+ it 'keeps sorting issues after visiting Projects Issues page' do
+ sorting_by('Oldest updated')
+ visit project_issues_path(project)
+
+ expect(find('.issues-filters')).to have_content('Oldest updated')
+ end
+ end
+
def show_milestone_dropdown
click_button 'Milestone'
expect(page).to have_selector('.dropdown-content', visible: true)
diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb
index f79fc1b5a01..a11499ba191 100644
--- a/spec/features/dashboard/issues_spec.rb
+++ b/spec/features/dashboard/issues_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Issues', feature: true do
+RSpec.describe 'Dashboard Issues' do
let(:current_user) { create :user }
+ let(:user) { current_user } # Shared examples depend on this being available
let!(:public_project) { create(:empty_project, :public) }
let(:project) { create(:empty_project) }
let(:project_with_issues_disabled) { create(:empty_project, :issues_disabled) }
@@ -12,7 +13,7 @@ RSpec.describe 'Dashboard Issues', feature: true do
before do
[project, project_with_issues_disabled].each { |project| project.team << [current_user, :master] }
- gitlab_sign_in(current_user)
+ sign_in(current_user)
visit issues_dashboard_path(assignee_id: current_user.id)
end
@@ -59,6 +60,11 @@ RSpec.describe 'Dashboard Issues', feature: true do
expect(page).to have_content(other_issue.title)
end
+ it 'state filter tabs work' do
+ find('#state-closed').click
+ expect(page).to have_current_path(issues_dashboard_url(assignee_id: current_user.id, state: 'closed'), url: true)
+ end
+
it_behaves_like "it has an RSS button with current_user's RSS token"
it_behaves_like "an autodiscoverable RSS feed with current_user's RSS token"
end
@@ -72,5 +78,17 @@ RSpec.describe 'Dashboard Issues', feature: true do
expect(page).not_to have_content(project_with_issues_disabled.name_with_namespace)
end
end
+
+ it 'shows the new issue page', :js do
+ find('.new-project-item-select-button').trigger('click')
+ wait_for_requests
+ find('.select2-results li').click
+
+ expect(page).to have_current_path("/#{project.path_with_namespace}/issues/new")
+
+ page.within('#content-body') do
+ expect(page).to have_selector('.issue-form')
+ end
+ end
end
end
diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb
index 88bbb9e75b9..8e19fb93665 100644
--- a/spec/features/dashboard/label_filter_spec.rb
+++ b/spec/features/dashboard/label_filter_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe 'Dashboard > label filter', feature: true, js: true do
+describe 'Dashboard > label filter', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, name: 'test', namespace: user.namespace) }
- let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) }
+ let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
+ let(:project2) { create(:empty_project, name: 'test2', path: 'test2', namespace: user.namespace) }
let(:label) { create(:label, title: 'bug', color: '#ff0000') }
let(:label2) { create(:label, title: 'bug') }
@@ -11,7 +11,7 @@ describe 'Dashboard > label filter', feature: true, js: true do
project.labels << label
project2.labels << label2
- gitlab_sign_in(user)
+ sign_in(user)
visit issues_dashboard_path
end
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index e521b6ed4bc..a406cd89ead 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -1,18 +1,25 @@
require 'spec_helper'
-describe 'Dashboard Merge Requests' do
+feature 'Dashboard Merge Requests' do
+ include FilterItemSelectHelper
+ include SortingHelper
+
let(:current_user) { create :user }
let(:project) { create(:empty_project) }
- let(:project_with_merge_requests_disabled) { create(:empty_project, :merge_requests_disabled) }
- before do
- [project, project_with_merge_requests_disabled].each { |project| project.team << [current_user, :master] }
+ let(:public_project) { create(:empty_project, :public, :repository) }
+ let(:forked_project) { Projects::ForkService.new(public_project, current_user).execute }
- gitlab_sign_in(current_user)
+ before do
+ project.add_master(current_user)
+ sign_in(current_user)
end
- describe 'new merge request dropdown' do
+ context 'new merge request dropdown' do
+ let(:project_with_disabled_merge_requests) { create(:empty_project, :merge_requests_disabled) }
+
before do
+ project_with_disabled_merge_requests.add_master(current_user)
visit merge_requests_dashboard_path
end
@@ -21,26 +28,103 @@ describe 'Dashboard Merge Requests' do
page.within('.select2-results') do
expect(page).to have_content(project.name_with_namespace)
- expect(page).not_to have_content(project_with_merge_requests_disabled.name_with_namespace)
+ expect(page).not_to have_content(project_with_disabled_merge_requests.name_with_namespace)
end
end
end
- it 'should show an empty state' do
- visit merge_requests_dashboard_path(assignee_id: current_user.id)
+ context 'no merge requests exist' do
+ it 'shows an empty state' do
+ visit merge_requests_dashboard_path(assignee_id: current_user.id)
- expect(page).to have_selector('.empty-state')
+ expect(page).to have_selector('.empty-state')
+ end
end
- context 'if there are merge requests' do
+ context 'merge requests exist' do
+ let!(:assigned_merge_request) do
+ create(:merge_request, assignee: current_user, target_project: project, source_project: project)
+ end
+
+ let!(:assigned_merge_request_from_fork) do
+ create(:merge_request,
+ source_branch: 'markdown', assignee: current_user,
+ target_project: public_project, source_project: forked_project
+ )
+ end
+
+ let!(:authored_merge_request) do
+ create(:merge_request,
+ source_branch: 'markdown', author: current_user,
+ target_project: project, source_project: project
+ )
+ end
+
+ let!(:authored_merge_request_from_fork) do
+ create(:merge_request,
+ source_branch: 'feature_conflict',
+ author: current_user,
+ target_project: public_project, source_project: forked_project
+ )
+ end
+
+ let!(:other_merge_request) do
+ create(:merge_request,
+ source_branch: 'fix',
+ target_project: project, source_project: project
+ )
+ end
+
before do
- create(:merge_request, assignee: current_user, source_project: project)
+ visit merge_requests_dashboard_path(assignee_id: current_user.id)
+ end
+
+ it 'shows assigned merge requests' do
+ expect(page).to have_content(assigned_merge_request.title)
+ expect(page).to have_content(assigned_merge_request_from_fork.title)
+
+ expect(page).not_to have_content(authored_merge_request.title)
+ expect(page).not_to have_content(authored_merge_request_from_fork.title)
+ expect(page).not_to have_content(other_merge_request.title)
+ end
+
+ it 'shows authored merge requests', js: true do
+ filter_item_select('Any Assignee', '.js-assignee-search')
+ filter_item_select(current_user.to_reference, '.js-author-search')
+
+ expect(page).to have_content(authored_merge_request.title)
+ expect(page).to have_content(authored_merge_request_from_fork.title)
+
+ expect(page).not_to have_content(assigned_merge_request.title)
+ expect(page).not_to have_content(assigned_merge_request_from_fork.title)
+ expect(page).not_to have_content(other_merge_request.title)
+ end
+
+ it 'shows all merge requests', js: true do
+ filter_item_select('Any Assignee', '.js-assignee-search')
+ filter_item_select('Any Author', '.js-author-search')
+
+ expect(page).to have_content(authored_merge_request.title)
+ expect(page).to have_content(authored_merge_request_from_fork.title)
+ expect(page).to have_content(assigned_merge_request.title)
+ expect(page).to have_content(assigned_merge_request_from_fork.title)
+ expect(page).to have_content(other_merge_request.title)
+ end
+
+ it 'shows sorted merge requests' do
+ sorting_by('Oldest updated')
visit merge_requests_dashboard_path(assignee_id: current_user.id)
+
+ expect(find('.issues-filters')).to have_content('Oldest updated')
end
- it 'should not show an empty state' do
- expect(page).not_to have_selector('.empty-state')
+ it 'keeps sorting merge requests after visiting Projects MR page' do
+ sorting_by('Oldest updated')
+
+ visit project_merge_requests_path(project)
+
+ expect(find('.issues-filters')).to have_content('Oldest updated')
end
end
end
diff --git a/spec/features/dashboard/milestone_filter_spec.rb b/spec/features/dashboard/milestone_filter_spec.rb
index 295262980a6..5ebef1eb097 100644
--- a/spec/features/dashboard/milestone_filter_spec.rb
+++ b/spec/features/dashboard/milestone_filter_spec.rb
@@ -1,15 +1,17 @@
require 'spec_helper'
-describe 'Dashboard > milestone filter', :feature, :js do
+feature 'Dashboard > milestone filter', :js do
+ include FilterItemSelectHelper
+
let(:user) { create(:user) }
- let(:project) { create(:project, name: 'test', namespace: user.namespace) }
- let(:milestone) { create(:milestone, title: "v1.0", project: project) }
- let(:milestone2) { create(:milestone, title: "v2.0", project: project) }
+ let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
+ let(:milestone) { create(:milestone, title: 'v1.0', project: project) }
+ let(:milestone2) { create(:milestone, title: 'v2.0', project: project) }
let!(:issue) { create :issue, author: user, project: project, milestone: milestone }
let!(:issue2) { create :issue, author: user, project: project, milestone: milestone2 }
before do
- gitlab_sign_in(user)
+ sign_in(user)
visit issues_dashboard_path(author_id: user.id)
end
@@ -22,17 +24,11 @@ describe 'Dashboard > milestone filter', :feature, :js do
end
context 'filtering by milestone' do
- milestone_select = '.js-milestone-select'
+ milestone_select_selector = '.js-milestone-select'
before do
- find(milestone_select).click
- wait_for_requests
-
- page.within('.dropdown-content') do
- click_link 'v1.0'
- end
-
- find(milestone_select).click
+ filter_item_select('v1.0', milestone_select_selector)
+ find(milestone_select_selector).click
wait_for_requests
end
@@ -49,7 +45,7 @@ describe 'Dashboard > milestone filter', :feature, :js do
expect(find('.milestone-filter')).not_to have_selector('.dropdown.open')
- find(milestone_select).click
+ find(milestone_select_selector).click
expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1)
expect(find('.dropdown-content a.is-active')).to have_content('v1.0')
diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb
index cc4193b180f..cf32d705365 100644
--- a/spec/features/dashboard/milestone_tabs_spec.rb
+++ b/spec/features/dashboard/milestone_tabs_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Dashboard milestone tabs', :js, :feature do
+describe 'Dashboard milestone tabs', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let!(:label) { create(:label, project: project) }
@@ -15,7 +15,7 @@ describe 'Dashboard milestone tabs', :js, :feature do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_milestone_path(milestone.safe_title, title: milestone.title)
end
diff --git a/spec/features/dashboard_milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb
index b308a2297b9..488f7397c69 100644
--- a/spec/features/dashboard_milestones_spec.rb
+++ b/spec/features/dashboard/milestones_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Dashboard > Milestones', feature: true do
+feature 'Dashboard > Milestones' do
describe 'as anonymous user' do
before do
visit dashboard_milestones_path
@@ -17,7 +17,7 @@ feature 'Dashboard > Milestones', feature: true do
let!(:milestone) { create(:milestone, project: project) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_milestones_path
end
diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb
index 0ba87d921d0..f3b538e490e 100644
--- a/spec/features/dashboard/project_member_activity_index_spec.rb
+++ b/spec/features/dashboard/project_member_activity_index_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Project member activity', feature: true, js: true do
+feature 'Project member activity', js: true do
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public, name: 'x', namespace: user.namespace) }
@@ -10,7 +10,7 @@ feature 'Project member activity', feature: true, js: true do
def visit_activities_and_wait_with_event(event_type)
Event.create(project: project, author_id: user.id, action: event_type)
- visit activity_namespace_project_path(project.namespace, project)
+ visit activity_project_path(project)
wait_for_requests
end
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 2a8185ca669..abb9e5eef96 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -1,13 +1,19 @@
require 'spec_helper'
-RSpec.describe 'Dashboard Projects', feature: true do
+feature 'Dashboard Projects' do
let(:user) { create(:user) }
- let(:project) { create(:project, name: "awesome stuff") }
+ let(:project) { create(:project, name: 'awesome stuff') }
let(:project2) { create(:project, :public, name: 'Community project') }
before do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
+ end
+
+ it_behaves_like "an autodiscoverable RSS feed with current_user's RSS token" do
+ before do
+ visit dashboard_projects_path
+ end
end
it 'shows the project the user in a member of in the list' do
@@ -15,13 +21,33 @@ RSpec.describe 'Dashboard Projects', feature: true do
expect(page).to have_content('awesome stuff')
end
- it 'shows the last_activity_at attribute as the update date' do
- now = Time.now
- project.update_column(:last_activity_at, now)
-
+ it 'shows "New project" button' do
visit dashboard_projects_path
- expect(page).to have_xpath("//time[@datetime='#{now.getutc.iso8601}']")
+ page.within '#content-body' do
+ expect(page).to have_link('New project')
+ end
+ end
+
+ context 'when last_repository_updated_at, last_activity_at and update_at are present' do
+ it 'shows the last_repository_updated_at attribute as the update date' do
+ project.update_attributes!(last_repository_updated_at: Time.now, last_activity_at: 1.hour.ago)
+
+ visit dashboard_projects_path
+
+ expect(page).to have_xpath("//time[@datetime='#{project.last_repository_updated_at.getutc.iso8601}']")
+ end
+ end
+
+ context 'when last_repository_updated_at and last_activity_at are missing' do
+ it 'shows the updated_at attribute as the update date' do
+ project.update_attributes!(last_repository_updated_at: nil, last_activity_at: nil)
+ project.touch
+
+ visit dashboard_projects_path
+
+ expect(page).to have_xpath("//time[@datetime='#{project.updated_at.getutc.iso8601}']")
+ end
end
context 'when on Starred projects tab' do
@@ -35,8 +61,8 @@ RSpec.describe 'Dashboard Projects', feature: true do
end
end
- describe "with a pipeline", redis: true do
- let!(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha) }
+ describe 'with a pipeline', clean_gitlab_redis_shared_state: true do
+ let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha) }
before do
# Since the cache isn't updated when a new pipeline is created
@@ -48,9 +74,50 @@ RSpec.describe 'Dashboard Projects', feature: true do
it 'shows that the last pipeline passed' do
visit dashboard_projects_path
- expect(page).to have_xpath("//a[@href='#{pipelines_namespace_project_commit_path(project.namespace, project, project.commit)}']")
+ page.within('.controls') do
+ expect(page).to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit)}']")
+ expect(page).to have_css('.ci-status-link')
+ expect(page).to have_css('.ci-status-icon-success')
+ expect(page).to have_link('Commit: passed')
+ end
end
end
- it_behaves_like "an autodiscoverable RSS feed with current_user's RSS token"
+ context 'last push widget' do
+ let(:push_event_data) do
+ {
+ before: Gitlab::Git::BLANK_SHA,
+ after: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e',
+ ref: 'refs/heads/feature',
+ user_id: user.id,
+ user_name: user.name,
+ repository: {
+ name: project.name,
+ url: 'localhost/rubinius',
+ description: '',
+ homepage: 'localhost/rubinius',
+ private: true
+ }
+ }
+ end
+ let!(:push_event) { create(:event, :pushed, data: push_event_data, project: project, author: user) }
+
+ before do
+ visit dashboard_projects_path
+ end
+
+ scenario 'shows "Create merge request" button' do
+ expect(page).to have_content 'You pushed to feature'
+
+ within('#content-body') do
+ find_link('Create merge request', visible: false).click
+ end
+
+ expect(page).to have_selector('.merge-request-form')
+ expect(current_path).to eq project_new_merge_request_path(project)
+ expect(find('#merge_request_target_project_id').value).to eq project.id.to_s
+ expect(find('input#merge_request_source_branch').value).to eq 'feature'
+ expect(find('input#merge_request_target_branch').value).to eq 'master'
+ end
+ end
end
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 525b0e1b210..5f1f0c10339 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-feature 'Dashboard shortcuts', :feature, :js do
+feature 'Dashboard shortcuts', :js do
context 'logged in' do
before do
- gitlab_sign_in :user
+ sign_in(create(:user))
visit root_dashboard_path
end
diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb
index 0c069ae5cf0..c29bcc7c9e9 100644
--- a/spec/features/dashboard/snippets_spec.rb
+++ b/spec/features/dashboard/snippets_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe 'Dashboard snippets', feature: true do
+describe 'Dashboard snippets' do
context 'when the project has snippets' do
let(:project) { create(:empty_project, :public) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
before do
allow(Snippet).to receive(:default_per_page).and_return(1)
- gitlab_sign_in(project.owner)
+ sign_in(project.owner)
visit dashboard_snippets_path
end
@@ -25,7 +25,7 @@ describe 'Dashboard snippets', feature: true do
end
before do
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_snippets_path
end
diff --git a/spec/features/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb
index 99b70b3d3a1..93da36c08fc 100644
--- a/spec/features/todos/target_state_spec.rb
+++ b/spec/features/dashboard/todos/target_state_spec.rb
@@ -1,12 +1,12 @@
require 'rails_helper'
-feature 'Todo target states', feature: true do
+feature 'Dashboard > Todo target states' do
let(:user) { create(:user) }
let(:author) { create(:user) }
- let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+ let(:project) { create(:empty_project, :public) }
before do
- gitlab_sign_in user
+ sign_in(user)
end
scenario 'on a closed issue todo has closed label' do
@@ -30,7 +30,7 @@ feature 'Todo target states', feature: true do
end
scenario 'on a merged merge request todo has merged label' do
- mr_merged = create(:merge_request, :simple, author: user, state: 'merged')
+ mr_merged = create(:merge_request, :simple, :merged, author: user)
create_todo mr_merged
visit dashboard_todos_path
@@ -40,7 +40,7 @@ feature 'Todo target states', feature: true do
end
scenario 'on a closed merge request todo has closed label' do
- mr_closed = create(:merge_request, :simple, author: user, state: 'closed')
+ mr_closed = create(:merge_request, :simple, :closed, author: user)
create_todo mr_closed
visit dashboard_todos_path
diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb
index 032fb479076..0a363259fe7 100644
--- a/spec/features/todos/todos_filtering_spec.rb
+++ b/spec/features/dashboard/todos/todos_filtering_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Dashboard > User filters todos', feature: true, js: true do
+feature 'Dashboard > User filters todos', js: true do
let(:user_1) { create(:user, username: 'user_1', name: 'user_1') }
let(:user_2) { create(:user, username: 'user_2', name: 'user_2') }
@@ -17,7 +17,7 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
project_1.team << [user_1, :developer]
project_2.team << [user_1, :developer]
- gitlab_sign_in(user_1)
+ sign_in(user_1)
visit dashboard_todos_path
end
@@ -34,7 +34,7 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
expect(page).not_to have_content project_2.name_with_namespace
end
- context "Author filter" do
+ context 'Author filter' do
it 'filters by author' do
click_button 'Author'
@@ -49,18 +49,18 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
expect(find('.todos-list')).not_to have_content 'issue'
end
- it "shows only authors of existing todos" do
+ it 'shows only authors of existing todos' do
click_button 'Author'
within '.dropdown-menu-author' do
- # It should contain two users + "Any Author"
+ # It should contain two users + 'Any Author'
expect(page).to have_selector('.dropdown-menu-user-link', count: 3)
expect(page).to have_content(user_1.name)
expect(page).to have_content(user_2.name)
end
end
- it "shows only authors of existing done todos" do
+ it 'shows only authors of existing done todos' do
user_3 = create :user
user_4 = create :user
create(:todo, user: user_1, author: user_3, project: project_1, target: issue, action: 1, state: :done)
@@ -74,7 +74,7 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
click_button 'Author'
within '.dropdown-menu-author' do
- # It should contain two users + "Any Author"
+ # It should contain two users + 'Any Author'
expect(page).to have_selector('.dropdown-menu-user-link', count: 3)
expect(page).to have_content(user_3.name)
expect(page).to have_content(user_4.name)
diff --git a/spec/features/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb
index 498bbac6d14..d49a78b290f 100644
--- a/spec/features/todos/todos_sorting_spec.rb
+++ b/spec/features/dashboard/todos/todos_sorting_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Dashboard > User sorts todos", feature: true do
+feature 'Dashboard > User sorts todos' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
@@ -18,7 +18,7 @@ describe "Dashboard > User sorts todos", feature: true do
let(:issue_3) { create(:issue, title: 'issue_3', project: project) }
let(:issue_4) { create(:issue, title: 'issue_4', project: project) }
- let!(:merge_request_1) { create(:merge_request, source_project: project, title: "merge_request_1") }
+ let!(:merge_request_1) { create(:merge_request, source_project: project, title: 'merge_request_1') }
before do
create(:todo, user: user, project: project, target: issue_4, created_at: 5.hours.ago)
@@ -32,41 +32,41 @@ describe "Dashboard > User sorts todos", feature: true do
issue_2.labels << label_3
issue_1.labels << label_2
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_todos_path
end
- it "sorts with oldest created todos first" do
- click_link "Last created"
+ it 'sorts with oldest created todos first' do
+ click_link 'Last created'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content("merge_request_1")
- expect(results_list.all('p')[1]).to have_content("issue_1")
- expect(results_list.all('p')[2]).to have_content("issue_3")
- expect(results_list.all('p')[3]).to have_content("issue_2")
- expect(results_list.all('p')[4]).to have_content("issue_4")
+ expect(results_list.all('p')[0]).to have_content('merge_request_1')
+ expect(results_list.all('p')[1]).to have_content('issue_1')
+ expect(results_list.all('p')[2]).to have_content('issue_3')
+ expect(results_list.all('p')[3]).to have_content('issue_2')
+ expect(results_list.all('p')[4]).to have_content('issue_4')
end
- it "sorts with newest created todos first" do
- click_link "Oldest created"
+ it 'sorts with newest created todos first' do
+ click_link 'Oldest created'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content("issue_4")
- expect(results_list.all('p')[1]).to have_content("issue_2")
- expect(results_list.all('p')[2]).to have_content("issue_3")
- expect(results_list.all('p')[3]).to have_content("issue_1")
- expect(results_list.all('p')[4]).to have_content("merge_request_1")
+ expect(results_list.all('p')[0]).to have_content('issue_4')
+ expect(results_list.all('p')[1]).to have_content('issue_2')
+ expect(results_list.all('p')[2]).to have_content('issue_3')
+ expect(results_list.all('p')[3]).to have_content('issue_1')
+ expect(results_list.all('p')[4]).to have_content('merge_request_1')
end
- it "sorts by label priority" do
- click_link "Label priority"
+ it 'sorts by label priority' do
+ click_link 'Label priority'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content("issue_3")
- expect(results_list.all('p')[1]).to have_content("merge_request_1")
- expect(results_list.all('p')[2]).to have_content("issue_1")
- expect(results_list.all('p')[3]).to have_content("issue_2")
- expect(results_list.all('p')[4]).to have_content("issue_4")
+ expect(results_list.all('p')[0]).to have_content('issue_3')
+ expect(results_list.all('p')[1]).to have_content('merge_request_1')
+ expect(results_list.all('p')[2]).to have_content('issue_1')
+ expect(results_list.all('p')[3]).to have_content('issue_2')
+ expect(results_list.all('p')[4]).to have_content('issue_4')
end
end
@@ -83,17 +83,17 @@ describe "Dashboard > User sorts todos", feature: true do
create(:todo, user: user, project: project, target: issue_2)
create(:todo, user: user, project: project, target: merge_request_1)
- gitlab_sign_in(user)
+ sign_in(user)
visit dashboard_todos_path
end
it "doesn't mix issues and merge requests label priorities" do
- click_link "Label priority"
+ click_link 'Label priority'
results_list = page.find('.todos-list')
- expect(results_list.all('p')[0]).to have_content("issue_1")
- expect(results_list.all('p')[1]).to have_content("issue_2")
- expect(results_list.all('p')[2]).to have_content("merge_request_1")
+ expect(results_list.all('p')[0]).to have_content('issue_1')
+ expect(results_list.all('p')[1]).to have_content('issue_2')
+ expect(results_list.all('p')[2]).to have_content('merge_request_1')
end
end
end
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
new file mode 100644
index 00000000000..c2a61cf5aff
--- /dev/null
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -0,0 +1,338 @@
+require 'spec_helper'
+
+feature 'Dashboard Todos' do
+ let(:user) { create(:user) }
+ let(:author) { create(:user) }
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, due_date: Date.today) }
+
+ context 'User does not have todos' do
+ before do
+ sign_in(user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows "All done" message' do
+ expect(page).to have_content 'Todos let you see what you should do next.'
+ end
+ end
+
+ context 'User has a todo', js: true do
+ before do
+ create(:todo, :mentioned, user: user, project: project, target: issue, author: author)
+ sign_in(user)
+
+ visit dashboard_todos_path
+ end
+
+ it 'has todo present' do
+ expect(page).to have_selector('.todos-list .todo', count: 1)
+ end
+
+ it 'shows due date as today' do
+ within first('.todo') do
+ expect(page).to have_content 'Due today'
+ end
+ end
+
+ shared_examples 'deleting the todo' do
+ before do
+ within first('.todo') do
+ click_link 'Done'
+ end
+ end
+
+ it 'is marked as done-reversible in the list' do
+ expect(page).to have_selector('.todos-list .todo.todo-pending.done-reversible')
+ end
+
+ it 'shows Undo button' do
+ expect(page).to have_selector('.js-undo-todo', visible: true)
+ expect(page).to have_selector('.js-done-todo', visible: false)
+ end
+
+ it 'updates todo count' do
+ expect(page).to have_content 'To do 0'
+ expect(page).to have_content 'Done 1'
+ end
+
+ it 'has not "All done" message' do
+ expect(page).not_to have_selector('.todos-all-done')
+ end
+ end
+
+ shared_examples 'deleting and restoring the todo' do
+ before do
+ within first('.todo') do
+ click_link 'Done'
+ wait_for_requests
+ click_link 'Undo'
+ end
+ end
+
+ it 'is marked back as pending in the list' do
+ expect(page).not_to have_selector('.todos-list .todo.todo-pending.done-reversible')
+ expect(page).to have_selector('.todos-list .todo.todo-pending')
+ end
+
+ it 'shows Done button' do
+ expect(page).to have_selector('.js-undo-todo', visible: false)
+ expect(page).to have_selector('.js-done-todo', visible: true)
+ end
+
+ it 'updates todo count' do
+ expect(page).to have_content 'To do 1'
+ expect(page).to have_content 'Done 0'
+ end
+ end
+
+ it_behaves_like 'deleting the todo'
+ it_behaves_like 'deleting and restoring the todo'
+
+ context 'todo is stale on the page' do
+ before do
+ todos = TodosFinder.new(user, state: :pending).execute
+ TodoService.new.mark_todos_as_done(todos, user)
+ end
+
+ it_behaves_like 'deleting the todo'
+ it_behaves_like 'deleting and restoring the todo'
+ end
+ end
+
+ context 'User created todos for themself' do
+ before do
+ sign_in(user)
+ end
+
+ context 'issue assigned todo' do
+ before do
+ create(:todo, :assigned, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows issue assigned to yourself message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You assigned issue #{issue.to_reference(full: true)} to yourself")
+ end
+ end
+ end
+
+ context 'marked todo' do
+ before do
+ create(:todo, :marked, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you added a todo message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You added a todo for issue #{issue.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+
+ context 'mentioned todo' do
+ before do
+ create(:todo, :mentioned, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you mentioned yourself message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+
+ context 'directly_addressed todo' do
+ before do
+ create(:todo, :directly_addressed, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you directly addressed yourself message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+
+ context 'approval todo' do
+ let(:merge_request) { create(:merge_request) }
+
+ before do
+ create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you set yourself as an approver message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+ end
+
+ context 'User has done todos', js: true do
+ before do
+ create(:todo, :mentioned, :done, user: user, project: project, target: issue, author: author)
+ sign_in(user)
+ visit dashboard_todos_path(state: :done)
+ end
+
+ it 'has the done todo present' do
+ expect(page).to have_selector('.todos-list .todo.todo-done', count: 1)
+ end
+
+ describe 'restoring the todo' do
+ before do
+ within first('.todo') do
+ click_link 'Add todo'
+ end
+ end
+
+ it 'is removed from the list' do
+ expect(page).not_to have_selector('.todos-list .todo.todo-done')
+ end
+
+ it 'updates todo count' do
+ expect(page).to have_content 'To do 1'
+ expect(page).to have_content 'Done 0'
+ end
+ end
+ end
+
+ context 'User has Todos with labels spanning multiple projects' do
+ before do
+ label1 = create(:label, project: project)
+ note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project)
+ create(:todo, :mentioned, project: project, target: issue, user: user, note_id: note1.id)
+
+ project2 = create(:empty_project, :public)
+ label2 = create(:label, project: project2)
+ issue2 = create(:issue, project: project2)
+ note2 = create(:note_on_issue, note: "Test #{label2.to_reference(format: :name)}", noteable_id: issue2.id, noteable_type: 'Issue', project: project2)
+ create(:todo, :mentioned, project: project2, target: issue2, user: user, note_id: note2.id)
+
+ gitlab_sign_in(user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows page with two Todos' do
+ expect(page).to have_selector('.todos-list .todo', count: 2)
+ end
+ end
+
+ context 'User has multiple pages of Todos' do
+ before do
+ allow(Todo).to receive(:default_per_page).and_return(1)
+
+ # Create just enough records to cause us to paginate
+ create_list(:todo, 2, :mentioned, user: user, project: project, target: issue, author: author)
+
+ sign_in(user)
+ end
+
+ it 'is paginated' do
+ visit dashboard_todos_path
+
+ expect(page).to have_selector('.gl-pagination')
+ end
+
+ it 'is has the right number of pages' do
+ visit dashboard_todos_path
+
+ expect(page).to have_selector('.gl-pagination .page', count: 2)
+ end
+
+ describe 'mark all as done', js: true do
+ before do
+ visit dashboard_todos_path
+ find('.js-todos-mark-all').trigger('click')
+ end
+
+ it 'shows "All done" message!' do
+ expect(page).to have_content 'To do 0'
+ expect(page).to have_content "You're all done!"
+ expect(page).not_to have_selector('.gl-pagination')
+ end
+
+ it 'shows "Undo mark all as done" button' do
+ expect(page).to have_selector('.js-todos-mark-all', visible: false)
+ expect(page).to have_selector('.js-todos-undo-all', visible: true)
+ end
+ end
+
+ describe 'undo mark all as done', js: true do
+ before do
+ visit dashboard_todos_path
+ end
+
+ it 'shows the restored todo list' do
+ mark_all_and_undo
+
+ expect(page).to have_selector('.todos-list .todo', count: 1)
+ expect(page).to have_selector('.gl-pagination')
+ expect(page).not_to have_content "You're all done!"
+ end
+
+ it 'updates todo count' do
+ mark_all_and_undo
+
+ expect(page).to have_content 'To do 2'
+ expect(page).to have_content 'Done 0'
+ end
+
+ it 'shows "Mark all as done" button' do
+ mark_all_and_undo
+
+ expect(page).to have_selector('.js-todos-mark-all', visible: true)
+ expect(page).to have_selector('.js-todos-undo-all', visible: false)
+ end
+
+ context 'User has deleted a todo' do
+ before do
+ within first('.todo') do
+ click_link 'Done'
+ end
+ end
+
+ it 'shows the restored todo list with the deleted todo' do
+ mark_all_and_undo
+
+ expect(page).to have_selector('.todos-list .todo.todo-pending', count: 1)
+ end
+ end
+
+ def mark_all_and_undo
+ find('.js-todos-mark-all').trigger('click')
+ wait_for_requests
+ find('.js-todos-undo-all').trigger('click')
+ wait_for_requests
+ end
+ end
+ end
+
+ context 'User has a Build Failed todo' do
+ let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) }
+
+ before do
+ sign_in(user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows the todo' do
+ expect(page).to have_content 'The build failed for merge request'
+ end
+
+ it 'links to the pipelines for the merge request' do
+ href = pipelines_project_merge_request_path(project, todo.target)
+
+ expect(page).to have_link "merge request #{todo.target.to_reference(full: true)}", href
+ end
+ end
+end
diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb
index e9f34760143..a88fe207e0e 100644
--- a/spec/features/dashboard/user_filters_projects_spec.rb
+++ b/spec/features/dashboard/user_filters_projects_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'Dashboard > User filters projects', :feature do
+describe 'Dashboard > User filters projects' do
let(:user) { create(:user) }
- let(:project) { create(:project, name: 'Victorialand', namespace: user.namespace) }
+ let(:project) { create(:empty_project, name: 'Victorialand', namespace: user.namespace) }
let(:user2) { create(:user) }
- let(:project2) { create(:project, name: 'Treasure', namespace: user2.namespace) }
+ let(:project2) { create(:empty_project, name: 'Treasure', namespace: user2.namespace) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'filtering personal projects' do
diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb
index 96128061e4d..fa83ad5d17c 100644
--- a/spec/features/discussion_comments/commit_spec.rb
+++ b/spec/features/discussion_comments/commit_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Discussion Comments Merge Request', :feature, :js do
+describe 'Discussion Comments Merge Request', :js do
include RepoHelpers
let(:user) { create(:user) }
@@ -9,9 +9,9 @@ describe 'Discussion Comments Merge Request', :feature, :js do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
+ visit project_commit_path(project, sample_commit.id)
end
it_behaves_like 'discussion comments', 'commit'
diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb
index d7c1cd12fb5..f52ba9c4d09 100644
--- a/spec/features/discussion_comments/issue_spec.rb
+++ b/spec/features/discussion_comments/issue_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'Discussion Comments Issue', :feature, :js do
+describe 'Discussion Comments Issue', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it_behaves_like 'discussion comments', 'issue'
diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb
index 31fb9c72d25..042f39f47e0 100644
--- a/spec/features/discussion_comments/merge_request_spec.rb
+++ b/spec/features/discussion_comments/merge_request_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'Discussion Comments Merge Request', :feature, :js do
+describe 'Discussion Comments Merge Request', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it_behaves_like 'discussion comments', 'merge request'
diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb
index 998d633c83d..50ba13499d9 100644
--- a/spec/features/discussion_comments/snippets_spec.rb
+++ b/spec/features/discussion_comments/snippets_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'Discussion Comments Issue', :feature, :js do
+describe 'Discussion Comments Issue', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:snippet) { create(:project_snippet, :private, project: project, author: user) }
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_snippet_path(project.namespace, project, snippet)
+ visit project_snippet_path(project, snippet)
end
it_behaves_like 'discussion comments', 'snippet'
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index ea749528c11..357d86497d9 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Expand and collapse diffs', js: true, feature: true do
+feature 'Expand and collapse diffs', js: true do
let(:branch) { 'expand-collapse-diffs' }
let(:project) { create(:project, :repository) }
@@ -10,11 +10,11 @@ feature 'Expand and collapse diffs', js: true, feature: true do
allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(100.kilobytes)
allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(10.kilobytes)
- gitlab_sign_in :admin
+ sign_in(create(:admin))
# Ensure that undiffable.md is in .gitattributes
project.repository.copy_gitattributes(branch)
- visit namespace_project_commit_path(project.namespace, project, project.commit(branch))
+ visit project_commit_path(project, project.commit(branch))
execute_script('window.ajaxUris = []; $(document).ajaxSend(function(event, xhr, settings) { ajaxUris.push(settings.url) });')
end
@@ -38,7 +38,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do
expect(large_diff).not_to have_selector('.code')
expect(large_diff).to have_selector('.nothing-here-block')
- visit namespace_project_commit_path(project.namespace, project, project.commit(branch), anchor: "#{large_diff[:id]}_0_1")
+ visit project_commit_path(project, project.commit(branch), anchor: "#{large_diff[:id]}_0_1")
execute_script('window.location.reload()')
wait_for_requests
@@ -52,7 +52,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do
expect(large_diff).not_to have_selector('.code')
expect(large_diff).to have_selector('.nothing-here-block')
- visit namespace_project_commit_path(project.namespace, project, project.commit(branch), anchor: large_diff[:id])
+ visit project_commit_path(project, project.commit(branch), anchor: large_diff[:id])
execute_script('window.location.reload()')
wait_for_requests
@@ -129,7 +129,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do
before do
large_diff.find('.diff-line-num', match: :prefer_exact).hover
- large_diff.find('.add-diff-note').click
+ large_diff.find('.add-diff-note', match: :prefer_exact).click
large_diff.find('.note-textarea').send_keys comment_text
large_diff.find_button('Comment').click
wait_for_requests
diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb
index 6be5dee0c3c..84f41eca999 100644
--- a/spec/features/explore/groups_list_spec.rb
+++ b/spec/features/explore/groups_list_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Explore Groups page', :js, :feature do
+describe 'Explore Groups page', :js do
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:public_group) { create(:group, :public) }
@@ -10,7 +10,7 @@ describe 'Explore Groups page', :js, :feature do
before do
group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit explore_groups_path
end
diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb
index 35c596d8578..a4c4d336807 100644
--- a/spec/features/explore/new_menu_spec.rb
+++ b/spec/features/explore/new_menu_spec.rb
@@ -1,22 +1,18 @@
require 'spec_helper'
-feature 'Top Plus Menu', feature: true, js: true do
- let(:user) { create :user }
- let(:guest_user) { create :user}
+feature 'Top Plus Menu', :js do
+ let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
- let(:public_project) { create(:project, :public) }
+ let(:public_project) { create(:empty_project, :public) }
before do
group.add_owner(user)
- group.add_guest(guest_user)
-
- project.add_guest(guest_user)
end
context 'used by full user' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'click on New project shows new project page' do
@@ -39,7 +35,7 @@ feature 'Top Plus Menu', feature: true, js: true do
scenario 'click on New snippet shows new snippet page' do
visit root_dashboard_path
-
+
click_topmenuitem("New snippet")
expect(page).to have_content('New Snippet')
@@ -47,7 +43,7 @@ feature 'Top Plus Menu', feature: true, js: true do
end
scenario 'click on New issue shows new issue page' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
click_topmenuitem("New issue")
@@ -56,7 +52,7 @@ feature 'Top Plus Menu', feature: true, js: true do
end
scenario 'click on New merge request shows new merge request page' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
click_topmenuitem("New merge request")
@@ -66,7 +62,7 @@ feature 'Top Plus Menu', feature: true, js: true do
end
scenario 'click on New project snippet shows new snippet page' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
page.within '.header-content' do
find('.header-new-dropdown-toggle').click
@@ -102,12 +98,17 @@ feature 'Top Plus Menu', feature: true, js: true do
end
context 'used by guest user' do
+ let(:guest_user) { create(:user) }
+
before do
- gitlab_sign_in(guest_user)
+ group.add_guest(guest_user)
+ project.add_guest(guest_user)
+
+ sign_in(guest_user)
end
scenario 'click on New issue shows new issue page' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
click_topmenuitem("New issue")
@@ -116,31 +117,31 @@ feature 'Top Plus Menu', feature: true, js: true do
end
scenario 'has no New merge request menu item' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
hasnot_topmenuitem("New merge request")
end
scenario 'has no New project snippet menu item' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet')
end
scenario 'public project has no New Issue Button' do
- visit namespace_project_path(public_project.namespace, public_project)
+ visit project_path(public_project)
hasnot_topmenuitem("New issue")
end
scenario 'public project has no New merge request menu item' do
- visit namespace_project_path(public_project.namespace, public_project)
+ visit project_path(public_project)
hasnot_topmenuitem("New merge request")
end
scenario 'public project has no New project snippet menu item' do
- visit namespace_project_path(public_project.namespace, public_project)
+ visit project_path(public_project)
expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet')
end
@@ -153,7 +154,7 @@ feature 'Top Plus Menu', feature: true, js: true do
scenario 'has no New project for group menu item' do
visit group_path(group)
-
+
expect(find('.header-new.dropdown')).not_to have_selector('.header-new-group-project')
end
end
@@ -168,5 +169,5 @@ feature 'Top Plus Menu', feature: true, js: true do
def hasnot_topmenuitem(item_name)
expect(find('.header-new.dropdown')).not_to have_content(item_name)
- end
+ end
end
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb
index 2d13af2a52a..300296a2b94 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/gitlab_flavored_markdown_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "GitLab Flavored Markdown", feature: true do
+describe "GitLab Flavored Markdown" do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
@@ -25,31 +25,31 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "renders title in commits#index" do
- visit namespace_project_commits_path(project.namespace, project, 'master', limit: 1)
+ visit project_commits_path(project, 'master', limit: 1)
expect(page).to have_link(issue.to_reference)
end
it "renders title in commits#show" do
- visit namespace_project_commit_path(project.namespace, project, commit)
+ visit project_commit_path(project, commit)
expect(page).to have_link(issue.to_reference)
end
it "renders description in commits#show" do
- visit namespace_project_commit_path(project.namespace, project, commit)
+ visit project_commit_path(project, commit)
expect(page).to have_link(fred.to_reference)
end
it "renders title in repositories#branches" do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
expect(page).to have_link(issue.to_reference)
end
end
- describe "for issues", feature: true, js: true do
+ describe "for issues", js: true do
before do
@other_issue = create(:issue,
author: user,
@@ -66,19 +66,19 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "renders subject in issues#index" do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
expect(page).to have_link(@other_issue.to_reference)
end
it "renders subject in issues#show" do
- visit namespace_project_issue_path(project.namespace, project, @issue)
+ visit project_issue_path(project, @issue)
expect(page).to have_link(@other_issue.to_reference)
end
it "renders details in issues#show" do
- visit namespace_project_issue_path(project.namespace, project, @issue)
+ visit project_issue_path(project, @issue)
expect(page).to have_link(fred.to_reference)
end
@@ -92,13 +92,13 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "renders title in merge_requests#index" do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
expect(page).to have_link(issue.to_reference)
end
it "renders title in merge_requests#show" do
- visit namespace_project_merge_request_path(project.namespace, project, @merge_request)
+ visit project_merge_request_path(project, @merge_request)
expect(page).to have_link(issue.to_reference)
end
@@ -113,19 +113,19 @@ describe "GitLab Flavored Markdown", feature: true do
end
it "renders title in milestones#index" do
- visit namespace_project_milestones_path(project.namespace, project)
+ visit project_milestones_path(project)
expect(page).to have_link(issue.to_reference)
end
it "renders title in milestones#show" do
- visit namespace_project_milestone_path(project.namespace, project, @milestone)
+ visit project_milestone_path(project, @milestone)
expect(page).to have_link(issue.to_reference)
end
it "renders description in milestones#show" do
- visit namespace_project_milestone_path(project.namespace, project, @milestone)
+ visit project_milestone_path(project, @milestone)
expect(page).to have_link(fred.to_reference)
end
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index 54ebfe6cf77..627a930c997 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Global search', feature: true do
+feature 'Global search' do
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'I search through the issues and I see pagination' do
diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb
new file mode 100644
index 00000000000..37814ba6238
--- /dev/null
+++ b/spec/features/group_variables_spec.rb
@@ -0,0 +1,78 @@
+require 'spec_helper'
+
+feature 'Group variables', js: true do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+
+ background do
+ group.add_master(user)
+ gitlab_sign_in(user)
+ end
+
+ context 'when user creates a new variable' do
+ background do
+ visit group_settings_ci_cd_path(group)
+ fill_in 'variable_key', with: 'AAA'
+ fill_in 'variable_value', with: 'AAA123'
+ find(:css, "#variable_protected").set(true)
+ click_on 'Add new variable'
+ end
+
+ scenario 'user sees the created variable' do
+ page.within('.variables-table') do
+ expect(find(".variable-key")).to have_content('AAA')
+ expect(find(".variable-value")).to have_content('******')
+ expect(find(".variable-protected")).to have_content('Yes')
+ end
+ click_on 'Reveal Values'
+ page.within('.variables-table') do
+ expect(find(".variable-value")).to have_content('AAA123')
+ end
+ end
+ end
+
+ context 'when user edits a variable' do
+ background do
+ create(:ci_group_variable, key: 'AAA', value: 'AAA123', protected: true,
+ group: group)
+
+ visit group_settings_ci_cd_path(group)
+
+ page.within('.variable-menu') do
+ click_on 'Update'
+ end
+
+ fill_in 'variable_key', with: 'BBB'
+ fill_in 'variable_value', with: 'BBB123'
+ find(:css, "#variable_protected").set(false)
+ click_on 'Save variable'
+ end
+
+ scenario 'user sees the updated variable' do
+ page.within('.variables-table') do
+ expect(find(".variable-key")).to have_content('BBB')
+ expect(find(".variable-value")).to have_content('******')
+ expect(find(".variable-protected")).to have_content('No')
+ end
+ end
+ end
+
+ context 'when user deletes a variable' do
+ background do
+ create(:ci_group_variable, key: 'BBB', value: 'BBB123', protected: false,
+ group: group)
+
+ visit group_settings_ci_cd_path(group)
+
+ page.within('.variable-menu') do
+ page.accept_alert 'Are you sure?' do
+ click_on 'Remove'
+ end
+ end
+ end
+
+ scenario 'user does not see the deleted variable' do
+ expect(page).to have_no_css('.variables-table')
+ end
+ end
+end
diff --git a/spec/features/groups/activity_spec.rb b/spec/features/groups/activity_spec.rb
index 9f66a3d8c72..d3b25ec3d6c 100644
--- a/spec/features/groups/activity_spec.rb
+++ b/spec/features/groups/activity_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Group activity page', feature: true do
+feature 'Group activity page' do
+ let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user }
let(:group) { create(:group) }
let(:path) { activity_group_path(group) }
context 'when signed in' do
before do
- user = create(:group_member, :developer, user: create(:user), group: group ).user
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb
index b1c7151dfa8..e2c7907528b 100644
--- a/spec/features/groups/empty_states_spec.rb
+++ b/spec/features/groups/empty_states_spec.rb
@@ -5,7 +5,7 @@ feature 'Groups Merge Requests Empty States' do
let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'group has a project' do
diff --git a/spec/features/groups/group_name_toggle_spec.rb b/spec/features/groups/group_name_toggle_spec.rb
index f450626c370..a7b8b702ab7 100644
--- a/spec/features/groups/group_name_toggle_spec.rb
+++ b/spec/features/groups/group_name_toggle_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Group name toggle', feature: true, js: true do
+feature 'Group name toggle', js: true do
let(:group) { create(:group) }
let(:nested_group_1) { create(:group, parent: group) }
let(:nested_group_2) { create(:group, parent: nested_group_1) }
@@ -9,7 +9,7 @@ feature 'Group name toggle', feature: true, js: true do
SMALL_SCREEN = 300
before do
- gitlab_sign_in :user
+ sign_in(create(:user))
end
it 'is not present if enough horizontal space' do
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index 5ad777248ec..121df1ec635 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Edit group settings', feature: true do
+feature 'Edit group settings' do
given(:user) { create(:user) }
given(:group) { create(:group, path: 'foo') }
background do
group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'when the group path is changed' do
@@ -18,14 +18,14 @@ feature 'Edit group settings', feature: true do
update_path(new_group_path)
visit new_group_full_path
expect(current_path).to eq(new_group_full_path)
- expect(find('h1.group-title')).to have_content(new_group_path)
+ expect(find('h1.group-title')).to have_content(group.name)
end
scenario 'the old group path redirects to the new path' do
update_path(new_group_path)
visit old_group_full_path
expect(current_path).to eq(new_group_full_path)
- expect(find('h1.group-title')).to have_content(new_group_path)
+ expect(find('h1.group-title')).to have_content(group.name)
end
context 'with a subgroup' do
@@ -37,19 +37,19 @@ feature 'Edit group settings', feature: true do
update_path(new_group_path)
visit new_subgroup_full_path
expect(current_path).to eq(new_subgroup_full_path)
- expect(find('h1.group-title')).to have_content(subgroup.path)
+ expect(find('h1.group-title')).to have_content(subgroup.name)
end
scenario 'the old subgroup path redirects to the new path' do
update_path(new_group_path)
visit old_subgroup_full_path
expect(current_path).to eq(new_subgroup_full_path)
- expect(find('h1.group-title')).to have_content(subgroup.path)
+ expect(find('h1.group-title')).to have_content(subgroup.name)
end
end
context 'with a project' do
- given!(:project) { create(:project, group: group, path: 'project') }
+ given!(:project) { create(:empty_project, group: group) }
given(:old_project_full_path) { "/#{group.path}/#{project.path}" }
given(:new_project_full_path) { "/#{new_group_path}/#{project.path}" }
@@ -65,14 +65,14 @@ feature 'Edit group settings', feature: true do
update_path(new_group_path)
visit new_project_full_path
expect(current_path).to eq(new_project_full_path)
- expect(find('h1.project-title')).to have_content(project.name)
+ expect(find('h1.title')).to have_content(project.path)
end
scenario 'the old project path redirects to the new path' do
update_path(new_group_path)
visit old_project_full_path
expect(current_path).to eq(new_project_full_path)
- expect(find('h1.project-title')).to have_content(project.name)
+ expect(find('h1.title')).to have_content(project.path)
end
end
end
diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb
index d6b88542ef7..449a99a2c7b 100644
--- a/spec/features/groups/issues_spec.rb
+++ b/spec/features/groups/issues_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Group issues page', feature: true do
+feature 'Group issues page' do
let(:path) { issues_group_path(group) }
let(:issuable) { create(:issue, project: project, title: "this is my created issuable")}
diff --git a/spec/features/groups/labels/edit_spec.rb b/spec/features/groups/labels/edit_spec.rb
index b33040ef843..fb338127861 100644
--- a/spec/features/groups/labels/edit_spec.rb
+++ b/spec/features/groups/labels/edit_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Edit group label', feature: true do
+feature 'Edit group label' do
given(:user) { create(:user) }
given(:group) { create(:group) }
given(:label) { create(:group_label, group: group) }
background do
group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit edit_group_label_path(group, label)
end
diff --git a/spec/features/groups/labels/subscription_spec.rb b/spec/features/groups/labels/subscription_spec.rb
new file mode 100644
index 00000000000..1dd09d4f203
--- /dev/null
+++ b/spec/features/groups/labels/subscription_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+feature 'Labels subscription' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let!(:feature) { create(:group_label, group: group, title: 'feature') }
+
+ context 'when signed in' do
+ before do
+ group.add_developer(user)
+ gitlab_sign_in user
+ end
+
+ scenario 'users can subscribe/unsubscribe to group labels', js: true do
+ visit group_labels_path(group)
+
+ expect(page).to have_content('feature')
+
+ within "#group_label_#{feature.id}" do
+ expect(page).not_to have_button 'Unsubscribe'
+
+ click_button 'Subscribe'
+
+ expect(page).not_to have_button 'Subscribe'
+ expect(page).to have_button 'Unsubscribe'
+
+ click_button 'Unsubscribe'
+
+ expect(page).to have_button 'Subscribe'
+ expect(page).not_to have_button 'Unsubscribe'
+ end
+ end
+ end
+
+ context 'when not signed in' do
+ it 'users can not subscribe/unsubscribe to labels' do
+ visit group_labels_path(group)
+
+ expect(page).to have_content 'feature'
+ expect(page).not_to have_button('Subscribe')
+ end
+ end
+
+ def click_link_on_dropdown(text)
+ find('.dropdown-group-label').click
+
+ page.within('.dropdown-group-label') do
+ find('a.js-subscribe-button', text: text).click
+ end
+ end
+end
diff --git a/spec/features/groups/members/last_owner_cannot_leave_group_spec.rb b/spec/features/groups/members/last_owner_cannot_leave_group_spec.rb
deleted file mode 100644
index 5af94e4069b..00000000000
--- a/spec/features/groups/members/last_owner_cannot_leave_group_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-feature 'Groups > Members > Last owner cannot leave group', feature: true do
- let(:owner) { create(:user) }
- let(:group) { create(:group) }
-
- background do
- group.add_owner(owner)
- gitlab_sign_in(owner)
- visit group_path(group)
- end
-
- scenario 'user does not see a "Leave group" link' do
- expect(page).not_to have_content 'Leave group'
- end
-end
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
new file mode 100644
index 00000000000..067a2dc850f
--- /dev/null
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+
+feature 'Groups > Members > Leave group' do
+ let(:user) { create(:user) }
+ let(:other_user) { create(:user) }
+ let(:group) { create(:group) }
+
+ background do
+ gitlab_sign_in(user)
+ end
+
+ scenario 'guest leaves the group' do
+ group.add_guest(user)
+ group.add_owner(other_user)
+
+ visit group_path(group)
+ click_link 'Leave group'
+
+ expect(current_path).to eq(dashboard_groups_path)
+ expect(page).to have_content left_group_message(group)
+ expect(group.users).not_to include(user)
+ end
+
+ scenario 'guest leaves the group as last member' do
+ group.add_guest(user)
+
+ visit group_path(group)
+ click_link 'Leave group'
+
+ expect(current_path).to eq(dashboard_groups_path)
+ expect(page).to have_content left_group_message(group)
+ expect(group.users).not_to include(user)
+ end
+
+ scenario 'owner leaves the group if they is not the last owner' do
+ group.add_owner(user)
+ group.add_owner(other_user)
+
+ visit group_path(group)
+ click_link 'Leave group'
+
+ expect(current_path).to eq(dashboard_groups_path)
+ expect(page).to have_content left_group_message(group)
+ expect(group.users).not_to include(user)
+ end
+
+ scenario 'owner can not leave the group if they is a last owner' do
+ group.add_owner(user)
+
+ visit group_path(group)
+
+ expect(page).not_to have_content 'Leave group'
+
+ visit group_group_members_path(group)
+
+ expect(find(:css, '.project-members-page li', text: user.name)).not_to have_selector(:css, 'a.btn-remove')
+ end
+
+ def left_group_message(group)
+ "You left the \"#{group.name}\""
+ end
+end
diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb
new file mode 100644
index 00000000000..5c5d48c3623
--- /dev/null
+++ b/spec/features/groups/members/list_members_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+feature 'Groups > Members > List members' do
+ include Select2Helper
+
+ let(:user1) { create(:user, name: 'John Doe') }
+ let(:user2) { create(:user, name: 'Mary Jane') }
+ let(:group) { create(:group) }
+ let(:nested_group) { create(:group, parent: group) }
+
+ background do
+ gitlab_sign_in(user1)
+ end
+
+ scenario 'show members from current group and parent', :nested_groups do
+ group.add_developer(user1)
+ nested_group.add_developer(user2)
+
+ visit group_group_members_path(nested_group)
+
+ expect(first_row.text).to include(user1.name)
+ expect(second_row.text).to include(user2.name)
+ end
+
+ scenario 'show user once if member of both current group and parent', :nested_groups do
+ group.add_developer(user1)
+ nested_group.add_developer(user1)
+
+ visit group_group_members_path(nested_group)
+
+ expect(first_row.text).to include(user1.name)
+ expect(second_row).to be_blank
+ end
+
+ def first_row
+ page.all('ul.content-list > li')[0]
+ end
+
+ def second_row
+ page.all('ul.content-list > li')[1]
+ end
+end
diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/manage_access_requests_spec.rb
index 4e4cf12e8af..b83cd657ef7 100644
--- a/spec/features/groups/members/owner_manages_access_requests_spec.rb
+++ b/spec/features/groups/members/manage_access_requests_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Groups > Members > Owner manages access requests', feature: true do
+feature 'Groups > Members > Manage access requests' do
let(:user) { create(:user) }
let(:owner) { create(:user) }
let(:group) { create(:group, :public, :access_requestable) }
@@ -8,7 +8,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do
background do
group.request_access(user)
group.add_owner(owner)
- gitlab_sign_in(owner)
+ sign_in(owner)
end
scenario 'owner can see access requests' do
@@ -17,7 +17,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do
expect_visible_access_request(group, user)
end
- scenario 'master can grant access' do
+ scenario 'owner can grant access' do
visit group_group_members_path(group)
expect_visible_access_request(group, user)
@@ -28,7 +28,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do
expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{group.name} group was granted"
end
- scenario 'master can deny access' do
+ scenario 'owner can deny access' do
visit group_group_members_path(group)
expect_visible_access_request(group, user)
diff --git a/spec/features/groups/members/list_spec.rb b/spec/features/groups/members/manage_members.rb
index 5d00ed30c83..9039b283393 100644
--- a/spec/features/groups/members/list_spec.rb
+++ b/spec/features/groups/members/manage_members.rb
@@ -1,35 +1,14 @@
require 'spec_helper'
-feature 'Groups members list', feature: true do
+feature 'Groups > Members > Manage members' do
include Select2Helper
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
let(:group) { create(:group) }
- let(:nested_group) { create(:group, parent: group) }
background do
- gitlab_sign_in(user1)
- end
-
- scenario 'show members from current group and parent', :nested_groups do
- group.add_developer(user1)
- nested_group.add_developer(user2)
-
- visit group_group_members_path(nested_group)
-
- expect(first_row.text).to include(user1.name)
- expect(second_row.text).to include(user2.name)
- end
-
- scenario 'show user once if member of both current group and parent', :nested_groups do
- group.add_developer(user1)
- nested_group.add_developer(user1)
-
- visit group_group_members_path(nested_group)
-
- expect(first_row.text).to include(user1.name)
- expect(second_row).to be_blank
+ sign_in(user1)
end
scenario 'update user to owner level', :js do
@@ -59,6 +38,18 @@ feature 'Groups members list', feature: true do
end
end
+ scenario 'remove user from group', :js do
+ group.add_owner(user1)
+ group.add_developer(user2)
+
+ visit group_group_members_path(group)
+
+ find(:css, '.project-members-page li', text: user2.name).find(:css, 'a.btn-remove').click
+
+ expect(page).not_to have_content(user2.name)
+ expect(group.users).not_to include(user2)
+ end
+
scenario 'add yourself to group when already an owner', :js do
group.add_owner(user1)
@@ -86,6 +77,23 @@ feature 'Groups members list', feature: true do
end
end
+ scenario 'guest can not manage other users' do
+ group.add_guest(user1)
+ group.add_developer(user2)
+
+ visit group_group_members_path(group)
+
+ expect(page).not_to have_button 'Add to group'
+
+ page.within(second_row) do
+ # Can not modify user2 role
+ expect(page).not_to have_button 'Developer'
+
+ # Can not remove user2
+ expect(page).not_to have_css('a.btn-remove')
+ end
+ end
+
def first_row
page.all('ul.content-list > li')[0]
end
diff --git a/spec/features/groups/members/member_cannot_request_access_to_his_project_spec.rb b/spec/features/groups/members/member_cannot_request_access_to_his_project_spec.rb
deleted file mode 100644
index 135bb3572bc..00000000000
--- a/spec/features/groups/members/member_cannot_request_access_to_his_project_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-feature 'Groups > Members > Member cannot request access to his project', feature: true do
- let(:member) { create(:user) }
- let(:group) { create(:group) }
-
- background do
- group.add_developer(member)
- gitlab_sign_in(member)
- visit group_path(group)
- end
-
- scenario 'member does not see the request access button' do
- expect(page).not_to have_content 'Request Access'
- end
-end
diff --git a/spec/features/groups/members/member_leaves_group_spec.rb b/spec/features/groups/members/member_leaves_group_spec.rb
deleted file mode 100644
index 40f3b166e74..00000000000
--- a/spec/features/groups/members/member_leaves_group_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'spec_helper'
-
-feature 'Groups > Members > Member leaves group', feature: true do
- let(:user) { create(:user) }
- let(:owner) { create(:user) }
- let(:group) { create(:group, :public) }
-
- background do
- group.add_owner(owner)
- group.add_developer(user)
- gitlab_sign_in(user)
- visit group_path(group)
- end
-
- scenario 'user leaves group' do
- click_link 'Leave group'
-
- expect(current_path).to eq(dashboard_groups_path)
- expect(group.users.exists?(user.id)).to be_falsey
- end
-end
diff --git a/spec/features/groups/members/user_requests_access_spec.rb b/spec/features/groups/members/request_access_spec.rb
index 3813308c237..6141981023c 100644
--- a/spec/features/groups/members/user_requests_access_spec.rb
+++ b/spec/features/groups/members/request_access_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-feature 'Groups > Members > User requests access', feature: true do
+feature 'Groups > Members > Request access' do
let(:user) { create(:user) }
let(:owner) { create(:user) }
let(:group) { create(:group, :public, :access_requestable) }
- let!(:project) { create(:project, :private, namespace: group) }
+ let!(:project) { create(:empty_project, :private, namespace: group) }
background do
group.add_owner(owner)
- gitlab_sign_in(user)
+ sign_in(user)
visit group_path(group)
end
@@ -68,4 +68,11 @@ feature 'Groups > Members > User requests access', feature: true do
expect(group.requesters.exists?(user_id: user)).to be_falsey
expect(page).to have_content 'Your access request to the group has been withdrawn.'
end
+
+ scenario 'member does not see the request access button' do
+ group.add_owner(user)
+ visit group_path(group)
+
+ expect(page).not_to have_content 'Request Access'
+ end
end
diff --git a/spec/features/groups/members/sorting_spec.rb b/spec/features/groups/members/sort_members_spec.rb
index 719fa0b40b8..e175ad04f86 100644
--- a/spec/features/groups/members/sorting_spec.rb
+++ b/spec/features/groups/members/sort_members_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Groups > Members > Sorting', feature: true do
+feature 'Groups > Members > Sort members' do
let(:owner) { create(:user, name: 'John Doe') }
let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) }
let(:group) { create(:group) }
@@ -9,7 +9,7 @@ feature 'Groups > Members > Sorting', feature: true do
create(:group_member, :owner, user: owner, group: group, created_at: 5.days.ago)
create(:group_member, :developer, user: developer, group: group, created_at: 3.days.ago)
- gitlab_sign_in(owner)
+ sign_in(owner)
end
scenario 'sorts alphabetically by default' do
@@ -68,7 +68,7 @@ feature 'Groups > Members > Sorting', feature: true do
expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Name, descending')
end
- scenario 'sorts by recent sign in', :redis do
+ scenario 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :recent_sign_in)
expect(first_member).to include(owner.name)
@@ -76,7 +76,7 @@ feature 'Groups > Members > Sorting', feature: true do
expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in')
end
- scenario 'sorts by oldest sign in', :redis do
+ scenario 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :oldest_sign_in)
expect(first_member).to include(developer.name)
diff --git a/spec/features/groups/merge_requests_spec.rb b/spec/features/groups/merge_requests_spec.rb
index b55078c3bf6..c2241feb9f7 100644
--- a/spec/features/groups/merge_requests_spec.rb
+++ b/spec/features/groups/merge_requests_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Group merge requests page', feature: true do
+feature 'Group merge requests page' do
let(:path) { merge_requests_group_path(group) }
let(:issuable) { create(:merge_request, source_project: project, target_project: project, title: 'this is my created issuable') }
include_examples 'project features apply to issuables', MergeRequest
context 'archived issuable' do
- let(:project_archived) { create(:project, :archived, :merge_requests_enabled, group: group) }
+ let(:project_archived) { create(:project, :archived, :merge_requests_enabled, :repository, group: group) }
let(:issuable_archived) { create(:merge_request, source_project: project_archived, target_project: project_archived, title: 'issuable of an archived project') }
let(:access_level) { ProjectFeature::ENABLED }
let(:user) { user_in_group }
diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb
index 330310eae6b..574bbe0e0e1 100644
--- a/spec/features/groups/milestone_spec.rb
+++ b/spec/features/groups/milestone_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'Group milestones', :feature, :js do
+feature 'Group milestones', :js do
let(:group) { create(:group) }
let!(:project) { create(:project_empty_repo, group: group) }
let(:user) { create(:group_member, :master, user: create(:user), group: group ).user }
@@ -8,7 +8,7 @@ feature 'Group milestones', :feature, :js do
before do
Timecop.freeze
- gitlab_sign_in(user)
+ sign_in(user)
end
after do
@@ -33,4 +33,32 @@ feature 'Group milestones', :feature, :js do
expect(find('.start_date')).to have_content(Date.today.at_beginning_of_month.strftime('%b %-d, %Y'))
end
end
+
+ context 'milestones list' do
+ let!(:other_project) { create(:project_empty_repo, group: group) }
+
+ let!(:active_group_milestone) { create(:milestone, group: group, state: 'active') }
+ let!(:active_project_milestone1) { create(:milestone, project: project, state: 'active', title: 'v1.0') }
+ let!(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.0') }
+ let!(:closed_group_milestone) { create(:milestone, group: group, state: 'closed') }
+ let!(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') }
+ let!(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') }
+
+ before do
+ visit group_milestones_path(group)
+ end
+
+ it 'counts milestones correctly' do
+ expect(find('.top-area .active .badge').text).to eq("2")
+ expect(find('.top-area .closed .badge').text).to eq("2")
+ expect(find('.top-area .all .badge').text).to eq("4")
+ end
+
+ it 'lists legacy group milestones and group milestones' do
+ legacy_milestone = GroupMilestone.build_collection(group, group.projects, { state: 'active' }).first
+
+ expect(page).to have_selector("#milestone_#{active_group_milestone.id}", count: 1)
+ expect(page).to have_selector("#milestone_#{legacy_milestone.milestones.first.id}", count: 1)
+ end
+ end
end
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index 76575f61528..303013e59d5 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -1,13 +1,16 @@
require 'spec_helper'
-feature 'Group show page', feature: true do
+feature 'Group show page' do
let(:group) { create(:group) }
let(:path) { group_path(group) }
context 'when signed in' do
+ let(:user) do
+ create(:group_member, :developer, user: create(:user), group: group ).user
+ end
+
before do
- user = create(:group_member, :developer, user: create(:user), group: group ).user
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index ecacca00a61..e59a484d992 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Group', feature: true do
+feature 'Group' do
before do
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
end
matcher :have_namespace_error_message do
@@ -108,8 +108,8 @@ feature 'Group', feature: true do
before do
group.add_owner(user)
- gitlab_sign_out
- gitlab_sign_in(user)
+ sign_out(:user)
+ sign_in(user)
visit subgroups_group_path(group)
click_link 'New Subgroup'
@@ -128,14 +128,14 @@ feature 'Group', feature: true do
it 'checks permissions to avoid exposing groups by parent_id' do
group = create(:group, :private, path: 'secret-group')
- gitlab_sign_out
- gitlab_sign_in(:user)
+ sign_out(:user)
+ sign_in(create(:user))
visit new_group_path(parent_id: group.id)
expect(page).not_to have_content('secret-group')
end
- describe 'group edit' do
+ describe 'group edit', js: true do
let(:group) { create(:group) }
let(:path) { edit_group_path(group) }
let(:new_name) { 'new-name' }
@@ -157,8 +157,8 @@ feature 'Group', feature: true do
end
it 'removes group' do
- click_link 'Remove group'
-
+ expect { remove_with_confirm('Remove group', group.path) }.to change {Group.count}.by(-1)
+ expect(group.members.all.count).to be_zero
expect(page).to have_content "scheduled for deletion"
end
end
@@ -212,4 +212,10 @@ feature 'Group', feature: true do
expect(page).to have_content(nested_group.name)
end
end
+
+ def remove_with_confirm(button_text, confirm_with)
+ click_button button_text
+ fill_in 'confirm_name_input', with: confirm_with
+ click_button 'Confirm'
+ end
end
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index b01ee1cf491..bd4f233cba9 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Help Pages', feature: true do
+describe 'Help Pages' do
describe 'Get the main help page' do
shared_examples_for 'help page' do |prefix: ''|
it 'prefixes links correctly' do
@@ -40,7 +40,7 @@ describe 'Help Pages', feature: true do
allow_any_instance_of(ApplicationSetting).to receive(:version_check_enabled) { true }
allow_any_instance_of(VersionCheck).to receive(:url) { '/version-check-url' }
- gitlab_sign_in :user
+ sign_in(create(:user))
visit help_path
end
@@ -60,7 +60,7 @@ describe 'Help Pages', feature: true do
allow_any_instance_of(ApplicationSetting).to receive(:help_page_text) { "My Custom Text" }
allow_any_instance_of(ApplicationSetting).to receive(:help_page_support_url) { "http://example.com/help" }
- gitlab_sign_in(:user)
+ sign_in(create(:user))
visit help_path
end
diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb
new file mode 100644
index 00000000000..0e43eed8699
--- /dev/null
+++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb
@@ -0,0 +1,116 @@
+require 'spec_helper'
+
+describe 'Issuables Close/Reopen/Report toggle' do
+ let(:user) { create(:user) }
+
+ shared_examples 'an issuable close/reopen/report toggle' do
+ let(:container) { find('.issuable-close-dropdown') }
+ let(:human_model_name) { issuable.model_name.human.downcase }
+
+ it 'shows toggle' do
+ expect(page).to have_link("Close #{human_model_name}")
+ expect(page).to have_selector('.issuable-close-dropdown')
+ end
+
+ it 'opens a dropdown when toggle is clicked' do
+ container.find('.dropdown-toggle').click
+
+ expect(container).to have_selector('.dropdown-menu')
+ expect(container).to have_content("Close #{human_model_name}")
+ expect(container).to have_content('Report abuse')
+ expect(container).to have_content("Report #{human_model_name.pluralize} that are abusive, inappropriate or spam.")
+ expect(container).to have_selector('.close-item.droplab-item-selected')
+ expect(container).to have_selector('.report-item')
+ expect(container).not_to have_selector('.report-item.droplab-item-selected')
+ expect(container).not_to have_selector('.reopen-item')
+ end
+
+ it 'changes the button when an item is selected' do
+ button = container.find('.issuable-close-button')
+
+ container.find('.dropdown-toggle').click
+ container.find('.report-item').click
+
+ expect(container).not_to have_selector('.dropdown-menu')
+ expect(button).to have_content('Report abuse')
+
+ container.find('.dropdown-toggle').click
+ container.find('.close-item').click
+
+ expect(button).to have_content("Close #{human_model_name}")
+ end
+ end
+
+ context 'on an issue' do
+ let(:project) { create(:empty_project) }
+ let(:issuable) { create(:issue, project: project) }
+
+ before do
+ project.add_master(user)
+ login_as user
+ end
+
+ context 'when user has permission to update', :js do
+ before do
+ visit project_issue_path(project, issuable)
+ end
+
+ it_behaves_like 'an issuable close/reopen/report toggle'
+ end
+
+ context 'when user doesnt have permission to update' do
+ let(:cant_project) { create(:empty_project) }
+ let(:cant_issuable) { create(:issue, project: cant_project) }
+
+ before do
+ cant_project.add_guest(user)
+
+ visit project_issue_path(cant_project, cant_issuable)
+ end
+
+ it 'only shows the `Report abuse` and `New issue` buttons' do
+ expect(page).to have_link('Report abuse')
+ expect(page).to have_link('New issue')
+ expect(page).not_to have_link('Close issue')
+ expect(page).not_to have_link('Reopen issue')
+ expect(page).not_to have_link('Edit')
+ end
+ end
+ end
+
+ context 'on a merge request' do
+ let(:project) { create(:project, :repository) }
+ let(:issuable) { create(:merge_request, source_project: project) }
+
+ before do
+ project.add_master(user)
+ login_as user
+ end
+
+ context 'when user has permission to update', :js do
+ before do
+ visit project_merge_request_path(project, issuable)
+ end
+
+ it_behaves_like 'an issuable close/reopen/report toggle'
+ end
+
+ context 'when user doesnt have permission to update' do
+ let(:cant_project) { create(:project, :repository) }
+ let(:cant_issuable) { create(:merge_request, source_project: cant_project) }
+
+ before do
+ cant_project.add_reporter(user)
+
+ visit project_merge_request_path(cant_project, cant_issuable)
+ end
+
+ it 'only shows a `Report abuse` button' do
+ expect(page).to have_link('Report abuse')
+ expect(page).not_to have_link('Close merge request')
+ expect(page).not_to have_link('Reopen merge request')
+ expect(page).not_to have_link('Edit')
+ end
+ end
+ end
+end
diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb
index 56c9b10e757..7c20c96528e 100644
--- a/spec/features/issuables/default_sort_order_spec.rb
+++ b/spec/features/issuables/default_sort_order_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Projects > Issuables > Default sort order', feature: true do
+describe 'Projects > Issuables > Default sort order' do
let(:project) { create(:empty_project, :public) }
let(:first_created_issuable) { issuables.order_created_asc.first }
diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb
index f3a5a8463d1..557de721222 100644
--- a/spec/features/issuables/issuable_list_spec.rb
+++ b/spec/features/issuables/issuable_list_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'issuable list', feature: true do
+describe 'issuable list' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -8,7 +8,7 @@ describe 'issuable list', feature: true do
before do
project.add_user(user, :developer)
- gitlab_sign_in(user)
+ sign_in(user)
issuable_types.each { |type| create_issuables(type) }
end
@@ -39,9 +39,9 @@ describe 'issuable list', feature: true do
def visit_issuable_list(issuable_type)
if issuable_type == :issue
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
else
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
end
diff --git a/spec/features/issuables/markdown_references_spec.rb b/spec/features/issuables/markdown_references_spec.rb
new file mode 100644
index 00000000000..169381d703a
--- /dev/null
+++ b/spec/features/issuables/markdown_references_spec.rb
@@ -0,0 +1,193 @@
+require 'rails_helper'
+
+describe 'Markdown References', :js do
+ let(:user) { create(:user) }
+ let(:actual_project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request, target_project: actual_project, source_project: actual_project)}
+ let(:issue_actual_project) { create(:issue, project: actual_project) }
+ let!(:other_project) { create(:empty_project, :public) }
+ let!(:issue_other_project) { create(:issue, project: other_project) }
+ let(:issues) { [issue_actual_project, issue_other_project] }
+
+ def build_note
+ markdown = "Referencing internal issue #{issue_actual_project.to_reference}, " +
+ "cross-project #{issue_other_project.to_reference(actual_project)} external JIRA-5 " +
+ "and non existing #999"
+
+ page.within('#diff-notes-app') do
+ fill_in 'note_note', with: markdown
+ end
+ end
+
+ shared_examples 'correct references' do
+ before do
+ remotelink = double(:remotelink, all: [], build: double(save!: true))
+
+ stub_request(:get, "https://jira.example.com/rest/api/2/issue/JIRA-5")
+ stub_request(:post, "https://jira.example.com/rest/api/2/issue/JIRA-5/comment")
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:remotelink).and_return(remotelink)
+
+ sign_in(user)
+ visit merge_request_path(merge_request)
+ build_note
+ end
+
+ def links_expectations
+ issues.each do |issue|
+ if referenced_issues.include?(issue)
+ expect(page).to have_link(issue.to_reference, href: issue_path(issue))
+ else
+ expect(page).not_to have_link(issue.to_reference, href: issue_path(issue))
+ end
+ end
+
+ if jira_referenced
+ expect(page).to have_link('JIRA-5', href: 'https://jira.example.com/browse/JIRA-5')
+ else
+ expect(page).not_to have_link('JIRA-5', href: 'https://jira.example.com/browse/JIRA-5')
+ end
+
+ expect(page).not_to have_link('#999')
+ end
+
+ it 'creates a link to the referenced issue on the preview' do
+ find('.js-md-preview-button').click
+ wait_for_requests
+
+ page.within('.md-preview-holder') do
+ links_expectations
+ end
+ end
+
+ it 'creates a link to the referenced issue after submit' do
+ click_button 'Comment'
+ wait_for_requests
+
+ page.within('#diff-notes-app') do
+ links_expectations
+ end
+ end
+
+ it 'creates a note on the referenced issues' do
+ click_button 'Comment'
+ wait_for_requests
+
+ if referenced_issues.include?(issue_actual_project)
+ visit issue_path(issue_actual_project)
+
+ page.within('#notes') do
+ expect(page).to have_content(
+ "#{user.to_reference} mentioned in merge request #{merge_request.to_reference}"
+ )
+ end
+ end
+
+ if referenced_issues.include?(issue_other_project)
+ visit issue_path(issue_other_project)
+
+ page.within('#notes') do
+ expect(page).to have_content(
+ "#{user.to_reference} mentioned in merge request #{merge_request.to_reference(other_project)}"
+ )
+ end
+ end
+ end
+ end
+
+ context 'when internal issues tracker is enabled for the other project' do
+ context 'when only internal issues tracker is enabled for the actual project' do
+ include_examples 'correct references' do
+ let(:referenced_issues) { [issue_actual_project, issue_other_project] }
+ let(:jira_referenced) { false }
+ end
+ end
+
+ context 'when both external and internal issues trackers are enabled for the actual project' do
+ before do
+ create(:jira_service, project: actual_project)
+ end
+
+ include_examples 'correct references' do
+ let(:referenced_issues) { [issue_actual_project, issue_other_project] }
+ let(:jira_referenced) { true }
+ end
+ end
+
+ context 'when only external issues tracker is enabled for the actual project' do
+ before do
+ create(:jira_service, project: actual_project)
+
+ actual_project.issues_enabled = false
+ actual_project.save!
+ end
+
+ include_examples 'correct references' do
+ let(:referenced_issues) { [issue_other_project] }
+ let(:jira_referenced) { true }
+ end
+ end
+
+ context 'when no tracker is enabled for the actual project' do
+ before do
+ actual_project.issues_enabled = false
+ actual_project.save!
+ end
+
+ include_examples 'correct references' do
+ let(:referenced_issues) { [issue_other_project] }
+ let(:jira_referenced) { false }
+ end
+ end
+ end
+
+ context 'when internal issues tracker is disabled for the other project' do
+ before do
+ other_project.issues_enabled = false
+ other_project.save!
+ end
+
+ context 'when only internal issues tracker is enabled for the actual project' do
+ include_examples 'correct references' do
+ let(:referenced_issues) { [issue_actual_project] }
+ let(:jira_referenced) { false }
+ end
+ end
+
+ context 'when both external and internal issues trackers are enabled for the actual project' do
+ before do
+ create(:jira_service, project: actual_project)
+ end
+
+ include_examples 'correct references' do
+ let(:referenced_issues) { [issue_actual_project] }
+ let(:jira_referenced) { true }
+ end
+ end
+
+ context 'when only external issues tracker is enabled for the actual project' do
+ before do
+ create(:jira_service, project: actual_project)
+
+ actual_project.issues_enabled = false
+ actual_project.save!
+ end
+
+ include_examples 'correct references' do
+ let(:referenced_issues) { [] }
+ let(:jira_referenced) { true }
+ end
+ end
+
+ context 'when no issues tracker is enabled for the actual project' do
+ before do
+ actual_project.issues_enabled = false
+ actual_project.save!
+ end
+
+ include_examples 'correct references' do
+ let(:referenced_issues) { [] }
+ let(:jira_referenced) { false }
+ end
+ end
+ end
+end
diff --git a/spec/features/issuables/user_sees_sidebar_spec.rb b/spec/features/issuables/user_sees_sidebar_spec.rb
new file mode 100644
index 00000000000..2bd1c8aab86
--- /dev/null
+++ b/spec/features/issuables/user_sees_sidebar_spec.rb
@@ -0,0 +1,30 @@
+require 'rails_helper'
+
+describe 'Issue Sidebar on Mobile' do
+ include MobileHelpers
+
+ let(:project) { create(:project, :public, :repository) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:issue) { create(:issue, project: project) }
+ let!(:user) { create(:user)}
+
+ before do
+ sign_in(user)
+ end
+
+ context 'mobile sidebar on merge requests', js: true do
+ before do
+ visit project_merge_request_path(merge_request.project, merge_request)
+ end
+
+ it_behaves_like "issue sidebar stays collapsed on mobile"
+ end
+
+ context 'mobile sidebar on issues', js: true do
+ before do
+ visit project_issue_path(project, issue)
+ end
+
+ it_behaves_like "issue sidebar stays collapsed on mobile"
+ end
+end
diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb
index 6698e2c79a1..6cb0bf6fdfd 100644
--- a/spec/features/issues/award_emoji_spec.rb
+++ b/spec/features/issues/award_emoji_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
-describe 'Awards Emoji', feature: true do
- let!(:project) { create(:project, :public) }
+describe 'Awards Emoji' do
+ let!(:project) { create(:empty_project, :public) }
let!(:user) { create(:user) }
let(:issue) do
create(:issue,
@@ -12,14 +12,14 @@ describe 'Awards Emoji', feature: true do
context 'authorized user' do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'visiting an issue with a legacy award emoji that is not valid anymore' do
before do
# The `heart_tip` emoji is not valid anymore so we need to skip validation
issue.award_emoji.build(user: user, name: 'heart_tip').save!(validate: false)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
wait_for_requests
end
@@ -33,7 +33,7 @@ describe 'Awards Emoji', feature: true do
let!(:note) { create(:note_on_issue, noteable: issue, project: issue.project, note: "Hello world") }
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
wait_for_requests
end
@@ -97,7 +97,7 @@ describe 'Awards Emoji', feature: true do
context 'unauthorized user', js: true do
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'has disabled emoji button' do
diff --git a/spec/features/issues/award_spec.rb b/spec/features/issues/award_spec.rb
index a1c97caea20..740281c1050 100644
--- a/spec/features/issues/award_spec.rb
+++ b/spec/features/issues/award_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-feature 'Issue awards', js: true, feature: true do
+feature 'Issue awards', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) }
describe 'logged in' do
before do
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
wait_for_requests
end
@@ -17,7 +17,7 @@ feature 'Issue awards', js: true, feature: true do
expect(page).to have_selector('.js-emoji-btn.active')
expect(first('.js-emoji-btn')).to have_content '1'
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(first('.js-emoji-btn')).to have_content '1'
end
@@ -26,7 +26,7 @@ feature 'Issue awards', js: true, feature: true do
find('.js-emoji-btn.active').click
expect(first('.js-emoji-btn')).to have_content '0'
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(first('.js-emoji-btn')).to have_content '0'
end
@@ -40,7 +40,7 @@ feature 'Issue awards', js: true, feature: true do
describe 'logged out' do
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
wait_for_requests
end
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index a99c19cb787..5acf8fdae84 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -1,8 +1,8 @@
require 'rails_helper'
-feature 'Issues > Labels bulk assignment', feature: true do
+feature 'Issues > Labels bulk assignment' do
let(:user) { create(:user) }
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:issue1) { create(:issue, project: project, title: "Issue 1") }
let!(:issue2) { create(:issue, project: project, title: "Issue 2") }
let!(:bug) { create(:label, project: project, title: 'bug') }
@@ -13,7 +13,7 @@ feature 'Issues > Labels bulk assignment', feature: true do
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'sidebar' do
@@ -346,9 +346,9 @@ feature 'Issues > Labels bulk assignment', feature: true do
context 'as a guest' do
before do
- gitlab_sign_in user
+ sign_in user
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
context 'cannot bulk assign labels' do
@@ -410,7 +410,7 @@ feature 'Issues > Labels bulk assignment', feature: true do
end
def enable_bulk_update
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_button 'Edit Issues'
end
diff --git a/spec/features/issues/create_branch_merge_request_spec.rb b/spec/features/issues/create_branch_merge_request_spec.rb
index aa538803dd8..f59f687cf51 100644
--- a/spec/features/issues/create_branch_merge_request_spec.rb
+++ b/spec/features/issues/create_branch_merge_request_spec.rb
@@ -1,41 +1,39 @@
require 'rails_helper'
-feature 'Create Branch/Merge Request Dropdown on issue page', feature: true, js: true do
+feature 'Create Branch/Merge Request Dropdown on issue page', js: true do
let(:user) { create(:user) }
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let(:issue) { create(:issue, project: project, title: 'Cherry-Coloured Funk') }
context 'for team members' do
before do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'allows creating a merge request from the issue page' do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
select_dropdown_option('create-mr')
+
+ expect(page).to have_content('WIP: Resolve "Cherry-Coloured Funk"')
+ expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first))
- wait_for_requests
+ visit project_issue_path(project, issue)
expect(page).to have_content("created branch 1-cherry-coloured-funk")
expect(page).to have_content("mentioned in merge request !1")
-
- visit namespace_project_merge_request_path(project.namespace, project, MergeRequest.first)
-
- expect(page).to have_content('WIP: Resolve "Cherry-Coloured Funk"')
- expect(current_path).to eq(namespace_project_merge_request_path(project.namespace, project, MergeRequest.first))
end
it 'allows creating a branch from the issue page' do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
select_dropdown_option('create-branch')
wait_for_requests
expect(page).to have_selector('.dropdown-toggle-text ', text: '1-cherry-coloured-funk')
- expect(current_path).to eq namespace_project_tree_path(project.namespace, project, '1-cherry-coloured-funk')
+ expect(current_path).to eq project_tree_path(project, '1-cherry-coloured-funk')
end
context "when there is a referenced merge request" do
@@ -52,7 +50,7 @@ feature 'Create Branch/Merge Request Dropdown on issue page', feature: true, js:
before do
referenced_mr.cache_merge_request_closes_issues!(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'disables the create branch button' do
@@ -66,7 +64,7 @@ feature 'Create Branch/Merge Request Dropdown on issue page', feature: true, js:
it 'disables the create branch button' do
issue = create(:issue, :confidential, project: project)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(page).not_to have_css('.create-mr-dropdown-wrap')
end
@@ -75,7 +73,7 @@ feature 'Create Branch/Merge Request Dropdown on issue page', feature: true, js:
context 'for visitors' do
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'shows no buttons' do
diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
index 5f631043e15..80cc8d22999 100644
--- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
@@ -1,21 +1,21 @@
require 'rails_helper'
-feature 'Resolving all open discussions in a merge request from an issue', feature: true, js: true do
+feature 'Resolving all open discussions in a merge request from an issue', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
describe 'as a user with access to the project' do
before do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in user
+ visit project_merge_request_path(project, merge_request)
end
it 'shows a button to resolve all discussions by creating a new issue' do
within('#resolve-count-app') do
- expect(page).to have_link "Resolve all discussions in new issue", href: new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ expect(page).to have_link "Resolve all discussions in new issue", href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
end
@@ -25,13 +25,13 @@ feature 'Resolving all open discussions in a merge request from an issue', featu
end
it 'hides the link for creating a new issue' do
- expect(page).not_to have_link "Resolve all discussions in new issue", href: new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ expect(page).not_to have_link "Resolve all discussions in new issue", href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
end
context 'creating an issue for discussions' do
before do
- click_link "Resolve all discussions in new issue", href: new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ click_link "Resolve all discussions in new issue", href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
it_behaves_like 'creating an issue for a discussion'
@@ -45,7 +45,7 @@ feature 'Resolving all open discussions in a merge request from an issue', featu
context 'with the internal tracker disabled' do
before do
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not show a link to create a new issue' do
@@ -55,7 +55,7 @@ feature 'Resolving all open discussions in a merge request from an issue', featu
context 'merge request has discussions that need to be resolved' do
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'shows a warning that the merge request contains unresolved discussions' do
@@ -64,13 +64,13 @@ feature 'Resolving all open discussions in a merge request from an issue', featu
it 'has a link to resolve all discussions by creating an issue' do
page.within '.mr-widget-body' do
- expect(page).to have_link 'Create an issue to resolve them later', href: new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ expect(page).to have_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
end
context 'creating an issue for discussions' do
before do
- page.click_link 'Create an issue to resolve them later', href: new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ page.click_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
it_behaves_like 'creating an issue for a discussion'
@@ -82,8 +82,8 @@ feature 'Resolving all open discussions in a merge request from an issue', featu
describe 'as a reporter' do
before do
project.team << [user, :reporter]
- gitlab_sign_in user
- visit new_namespace_project_issue_path(project.namespace, project, merge_request_to_resolve_discussions_of: merge_request.iid)
+ sign_in user
+ visit new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
it 'Shows a notice to ask someone else to resolve the discussions' do
diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
index 9e9e214060f..ad5fd0fd97b 100644
--- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
@@ -1,22 +1,22 @@
require 'rails_helper'
-feature 'Resolve an open discussion in a merge request by creating an issue', feature: true do
+feature 'Resolve an open discussion in a merge request by creating an issue' do
let(:user) { create(:user) }
- let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: true) }
+ let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: true) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
describe 'As a user with access to the project' do
before do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in user
+ visit project_merge_request_path(project, merge_request)
end
context 'with the internal tracker disabled' do
before do
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not show a link to create a new issue' do
@@ -43,14 +43,14 @@ feature 'Resolve an open discussion in a merge request by creating an issue', fe
end
it 'has a link to create a new issue for a discussion' do
- new_issue_link = new_namespace_project_issue_path(project.namespace, project, discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid)
+ new_issue_link = new_project_issue_path(project, discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid)
expect(page).to have_link 'Resolve this discussion in a new issue', href: new_issue_link
end
context 'creating the issue' do
before do
- click_link 'Resolve this discussion in a new issue', href: new_namespace_project_issue_path(project.namespace, project, discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid)
+ click_link 'Resolve this discussion in a new issue', href: new_project_issue_path(project, discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid)
end
it 'has a hidden field for the discussion' do
@@ -66,10 +66,9 @@ feature 'Resolve an open discussion in a merge request by creating an issue', fe
describe 'as a reporter' do
before do
project.team << [user, :reporter]
- gitlab_sign_in user
- visit new_namespace_project_issue_path(project.namespace, project,
- merge_request_to_resolve_discussions_of: merge_request.iid,
- discussion_to_resolve: discussion.id)
+ sign_in user
+ visit new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid,
+ discussion_to_resolve: discussion.id)
end
it 'Shows a notice to ask someone else to resolve the discussions' do
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 96f6739af2d..a403d885de0 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Dropdown assignee', :feature, :js do
+describe 'Dropdown assignee', :js do
include FilteredSearchHelpers
let!(:project) { create(:empty_project) }
@@ -23,10 +23,10 @@ describe 'Dropdown assignee', :feature, :js do
project.team << [user, :master]
project.team << [user_john, :master]
project.team << [user_jacob, :master]
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'behavior' do
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index 5ee824c662a..b7d9bbd7e1d 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Dropdown author', js: true, feature: true do
+describe 'Dropdown author', js: true do
include FilteredSearchHelpers
let!(:project) { create(:empty_project) }
@@ -31,10 +31,10 @@ describe 'Dropdown author', js: true, feature: true do
project.team << [user, :master]
project.team << [user_john, :master]
project.team << [user_jacob, :master]
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'behavior' do
diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
index a05e4394ffd..292fd683271 100644
--- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Dropdown hint', :js, :feature do
+describe 'Dropdown hint', :js do
include FilteredSearchHelpers
let!(:project) { create(:empty_project) }
@@ -14,10 +14,10 @@ describe 'Dropdown hint', :js, :feature do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'behavior' do
diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb
index aec9d7ceb5d..e8f005d7752 100644
--- a/spec/features/issues/filtered_search/dropdown_label_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Dropdown label', js: true, feature: true do
+describe 'Dropdown label', js: true do
include FilteredSearchHelpers
let(:project) { create(:empty_project) }
@@ -34,10 +34,10 @@ describe 'Dropdown label', js: true, feature: true do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'keyboard navigation' do
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index b21f41946b7..ace73f4b1a6 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Dropdown milestone', :feature, :js do
+describe 'Dropdown milestone', :js do
include FilteredSearchHelpers
let!(:project) { create(:empty_project) }
@@ -30,10 +30,10 @@ describe 'Dropdown milestone', :feature, :js do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'behavior' do
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index 863f8f75cd8..265bcb3a8e5 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe 'Filter issues', js: true, feature: true do
+describe 'Filter issues', js: true do
include Devise::Test::IntegrationHelpers
include FilteredSearchHelpers
let!(:group) { create(:group) }
- let!(:project) { create(:project, group: group) }
+ let!(:project) { create(:empty_project, group: group) }
let!(:user) { create(:user, username: 'joe', name: 'Joe') }
let!(:user2) { create(:user, username: 'jane') }
let!(:label) { create(:label, project: project) }
@@ -89,7 +89,7 @@ describe 'Filter issues', js: true, feature: true do
milestone: future_milestone,
project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'filter issues by author' do
@@ -459,7 +459,7 @@ describe 'Filter issues', js: true, feature: true do
context 'issue label clicked' do
before do
- find('.issues-list .issue .issue-info a .label', text: multiple_words_label.title).click
+ find('.issues-list .issue .issue-main-info .issuable-info a .label', text: multiple_words_label.title).click
end
it 'filters' do
@@ -804,7 +804,7 @@ describe 'Filter issues', js: true, feature: true do
describe 'RSS feeds' do
it 'updates atom feed link for project issues' do
- visit namespace_project_issues_path(project.namespace, project, milestone_title: milestone.title, assignee_id: user.id)
+ visit project_issues_path(project, milestone_title: milestone.title, assignee_id: user.id)
link = find_link('Subscribe')
params = CGI.parse(URI.parse(link[:href]).query)
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
@@ -836,7 +836,7 @@ describe 'Filter issues', js: true, feature: true do
context 'URL has a trailing slash' do
before do
- visit "#{namespace_project_issues_path(project.namespace, project)}/"
+ visit "#{project_issues_path(project)}/"
end
it 'milestone dropdown loads milestones' do
diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb
index 89856fe4739..51c0be69abc 100644
--- a/spec/features/issues/filtered_search/recent_searches_spec.rb
+++ b/spec/features/issues/filtered_search/recent_searches_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Recent searches', js: true, feature: true do
+describe 'Recent searches', js: true do
include FilteredSearchHelpers
let(:project_1) { create(:empty_project, :public) }
@@ -22,7 +22,7 @@ describe 'Recent searches', js: true, feature: true do
end
it 'searching adds to recent searches' do
- visit namespace_project_issues_path(project_1.namespace, project_1)
+ visit project_issues_path(project_1)
input_filtered_search('foo', submit: true)
input_filtered_search('bar', submit: true)
@@ -35,8 +35,8 @@ describe 'Recent searches', js: true, feature: true do
end
it 'visiting URL with search params adds to recent searches' do
- visit namespace_project_issues_path(project_1.namespace, project_1, label_name: 'foo', search: 'bar')
- visit namespace_project_issues_path(project_1.namespace, project_1, label_name: 'qux', search: 'garply')
+ visit project_issues_path(project_1, label_name: 'foo', search: 'bar')
+ visit project_issues_path(project_1, label_name: 'qux', search: 'garply')
items = all('.filtered-search-history-dropdown-item', visible: false)
@@ -48,7 +48,7 @@ describe 'Recent searches', js: true, feature: true do
it 'saved recent searches are restored last on the list' do
set_recent_searches(project_1_local_storage_key, '["saved1", "saved2"]')
- visit namespace_project_issues_path(project_1.namespace, project_1, search: 'foo')
+ visit project_issues_path(project_1, search: 'foo')
items = all('.filtered-search-history-dropdown-item', visible: false)
@@ -59,12 +59,12 @@ describe 'Recent searches', js: true, feature: true do
end
it 'searches are scoped to projects' do
- visit namespace_project_issues_path(project_1.namespace, project_1)
+ visit project_issues_path(project_1)
input_filtered_search('foo', submit: true)
input_filtered_search('bar', submit: true)
- visit namespace_project_issues_path(project_2.namespace, project_2)
+ visit project_issues_path(project_2)
input_filtered_search('more', submit: true)
input_filtered_search('things', submit: true)
@@ -78,7 +78,7 @@ describe 'Recent searches', js: true, feature: true do
it 'clicking item fills search input' do
set_recent_searches(project_1_local_storage_key, '["foo", "bar"]')
- visit namespace_project_issues_path(project_1.namespace, project_1)
+ visit project_issues_path(project_1)
all('.filtered-search-history-dropdown-item', visible: false)[0].click
wait_for_filtered_search('foo')
@@ -88,7 +88,7 @@ describe 'Recent searches', js: true, feature: true do
it 'clear recent searches button, clears recent searches' do
set_recent_searches(project_1_local_storage_key, '["foo"]')
- visit namespace_project_issues_path(project_1.namespace, project_1)
+ visit project_issues_path(project_1)
items_before = all('.filtered-search-history-dropdown-item', visible: false)
@@ -102,7 +102,7 @@ describe 'Recent searches', js: true, feature: true do
it 'shows flash error when failed to parse saved history' do
set_recent_searches(project_1_local_storage_key, 'fail')
- visit namespace_project_issues_path(project_1.namespace, project_1)
+ visit project_issues_path(project_1)
expect(find('.flash-alert')).to have_text('An error occured while parsing recent searches')
end
diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb
index 806c732b935..115875d72ce 100644
--- a/spec/features/issues/filtered_search/search_bar_spec.rb
+++ b/spec/features/issues/filtered_search/search_bar_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Search bar', js: true, feature: true do
+describe 'Search bar', js: true do
include FilteredSearchHelpers
let!(:project) { create(:empty_project) }
@@ -9,10 +9,10 @@ describe 'Search bar', js: true, feature: true do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
def get_left_style(style)
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index 22488f34813..d00d0a9c81b 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Visual tokens', js: true, feature: true do
+describe 'Visual tokens', js: true do
include FilteredSearchHelpers
include WaitForRequests
@@ -25,10 +25,10 @@ describe 'Visual tokens', js: true, feature: true do
before do
project.add_user(user, :master)
project.add_user(user_rock, :master)
- gitlab_sign_in(user)
+ sign_in(user)
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
end
describe 'editing author token' do
@@ -133,7 +133,7 @@ describe 'Visual tokens', js: true, feature: true do
describe 'editing milestone token' do
before do
input_filtered_search('milestone:%10.0 author:none', submit: false)
- first('.tokens-container .filtered-search-token').double_click
+ first('.tokens-container .filtered-search-token').click
first('#js-dropdown-milestone .filter-dropdown .filter-dropdown-item')
end
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index b369ef1ff79..0ba02ba42ba 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -1,11 +1,10 @@
require 'rails_helper'
-describe 'New/edit issue', :feature, :js do
- include GitlabRoutingHelper
+describe 'New/edit issue', :js do
include ActionView::Helpers::JavaScriptHelper
include FormHelper
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:user) { create(:user)}
let!(:user2) { create(:user)}
let!(:milestone) { create(:milestone, project: project) }
@@ -16,30 +15,30 @@ describe 'New/edit issue', :feature, :js do
before do
project.team << [user, :master]
project.team << [user2, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'new issue' do
before do
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
end
- describe 'shorten users API pagination limit (CE)' do
+ describe 'shorten users API pagination limit' do
before do
# Using `allow_any_instance_of`/`and_wrap_original`, `original` would
# somehow refer to the very block we defined to _wrap_ that method, instead of
# the original method, resulting in infinite recurison when called.
# This is likely a bug with helper modules included into dynamically generated view classes.
# To work around this, we have to hold on to and call to the original implementation manually.
- original_issue_dropdown_options = FormHelper.instance_method(:issue_dropdown_options)
- allow_any_instance_of(FormHelper).to receive(:issue_dropdown_options).and_wrap_original do |original, *args|
+ original_issue_dropdown_options = FormHelper.instance_method(:issue_assignees_dropdown_options)
+ allow_any_instance_of(FormHelper).to receive(:issue_assignees_dropdown_options).and_wrap_original do |original, *args|
options = original_issue_dropdown_options.bind(original.receiver).call(*args)
options[:data][:per_page] = 2
options
end
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
click_button 'Unassigned'
@@ -64,7 +63,7 @@ describe 'New/edit issue', :feature, :js do
end
end
- describe 'single assignee (CE)' do
+ describe 'single assignee' do
before do
click_button 'Unassigned'
@@ -221,7 +220,7 @@ describe 'New/edit issue', :feature, :js do
context 'edit issue' do
before do
- visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ visit edit_project_issue_path(project, issue)
end
it 'allows user to update issue' do
@@ -282,7 +281,7 @@ describe 'New/edit issue', :feature, :js do
before do
sub_group_project.add_master(user)
- visit new_namespace_project_issue_path(sub_group_project.namespace, sub_group_project)
+ visit new_project_issue_path(sub_group_project)
end
it 'creates new label from dropdown' do
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index e61eb5233d0..1b36f16e8b6 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -1,19 +1,31 @@
require 'rails_helper'
-feature 'GFM autocomplete', feature: true, js: true do
+feature 'GFM autocomplete', js: true do
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:label) { create(:label, project: project, title: 'special+') }
let(:issue) { create(:issue, project: project) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
wait_for_requests
end
+ it 'updates issue descripton with GFM reference' do
+ find('.issuable-edit').click
+
+ find('#issue-description').native.send_keys("@#{user.name[0...3]}")
+
+ find('.atwho-view .cur').trigger('click')
+
+ click_button 'Save changes'
+
+ expect(find('.description')).to have_content(user.to_reference)
+ end
+
it 'opens autocomplete menu when field starts with text' do
page.within '.timeline-content-form' do
find('#note_note').native.send_keys('')
diff --git a/spec/features/issues/group_label_sidebar_spec.rb b/spec/features/issues/group_label_sidebar_spec.rb
index fc8515cfe9b..a8ac1d605cb 100644
--- a/spec/features/issues/group_label_sidebar_spec.rb
+++ b/spec/features/issues/group_label_sidebar_spec.rb
@@ -1,18 +1,14 @@
require 'rails_helper'
-describe 'Group label on issue', :feature do
+describe 'Group label on issue' do
it 'renders link to the project issues page' do
group = create(:group)
project = create(:empty_project, :public, namespace: group)
feature = create(:group_label, group: group, title: 'feature')
issue = create(:labeled_issue, project: project, labels: [feature])
- label_link = namespace_project_issues_path(
- project.namespace,
- project,
- label_name: [feature.name]
- )
+ label_link = project_issues_path(project, label_name: [feature.name])
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
link = find('.issuable-show-labels a')
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
new file mode 100644
index 00000000000..a7a7e02b59c
--- /dev/null
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -0,0 +1,43 @@
+require 'rails_helper'
+
+feature 'Issue Detail', :js do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, project: project, author: user) }
+
+ context 'when user displays the issue' do
+ before do
+ visit project_issue_path(project, issue)
+ wait_for_requests
+ end
+
+ it 'shows the issue' do
+ page.within('.issuable-details') do
+ expect(find('h2')).to have_content(issue.title)
+ end
+ end
+ end
+
+ context 'when edited by a user who is later deleted' do
+ before do
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ wait_for_requests
+
+ click_link 'Edit'
+ fill_in 'issue-title', with: 'issue title'
+ click_button 'Save'
+
+ visit profile_account_path
+ click_link 'Delete account'
+
+ visit project_issue_path(project, issue)
+ end
+
+ it 'shows the issue' do
+ page.within('.issuable-details') do
+ expect(find('h2')).to have_content(issue.reload.title)
+ end
+ end
+ end
+end
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index a01ca16ceec..50aa5fbb790 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -1,16 +1,16 @@
require 'rails_helper'
-feature 'Issue Sidebar', feature: true do
+feature 'Issue Sidebar' do
include MobileHelpers
let(:group) { create(:group, :nested) }
- let(:project) { create(:project, :public, namespace: group) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
let(:issue) { create(:issue, project: project) }
let!(:user) { create(:user)}
let!(:label) { create(:label, project: project, title: 'bug') }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'assignee', js: true do
@@ -154,20 +154,6 @@ feature 'Issue Sidebar', feature: true do
end
end
- context 'as a allowed mobile user', js: true do
- before do
- project.team << [user, :developer]
- resize_screen_xs
- visit_issue(project, issue)
- end
-
- context 'mobile sidebar' do
- it 'collapses the sidebar for small screens' do
- expect(page).not_to have_css('aside.right-sidebar.right-sidebar-collapsed')
- end
- end
- end
-
context 'as a guest' do
before do
project.team << [user, :guest]
@@ -180,7 +166,7 @@ feature 'Issue Sidebar', feature: true do
end
def visit_issue(project, issue)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
def open_issue_sidebar
diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb
index 66d823ec9d0..0f869970460 100644
--- a/spec/features/issues/markdown_toolbar_spec.rb
+++ b/spec/features/issues/markdown_toolbar_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-feature 'Issue markdown toolbar', feature: true, js: true do
- let(:project) { create(:project, :public) }
+feature 'Issue markdown toolbar', js: true do
+ let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) }
- let(:user) { create(:user) }
+ let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it "doesn't include first new line when adding bold" do
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index 21a7637fe7f..2ab7d1a71b7 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -2,14 +2,14 @@ require 'rails_helper'
feature 'issue move to another project' do
let(:user) { create(:user) }
- let(:old_project) { create(:project) }
+ let(:old_project) { create(:project, :repository) }
let(:text) { 'Some issue description' }
let(:issue) do
create(:issue, description: text, project: old_project, author: user)
end
- background { gitlab_sign_in(user) }
+ background { sign_in(user) }
context 'user does not have permission to move issue' do
background do
@@ -25,8 +25,8 @@ feature 'issue move to another project' do
context 'user has permission to move issue' do
let!(:mr) { create(:merge_request, source_project: old_project) }
- let(:new_project) { create(:project) }
- let(:new_project_search) { create(:project) }
+ let(:new_project) { create(:empty_project) }
+ let(:new_project_search) { create(:empty_project) }
let(:text) { "Text with #{mr.to_reference}" }
let(:cross_reference) { old_project.to_reference(new_project) }
@@ -41,13 +41,10 @@ feature 'issue move to another project' do
find('#issuable-move', visible: false).set(new_project.id)
click_button('Save changes')
- wait_for_requests
-
- expect(current_url).to include project_path(new_project)
-
expect(page).to have_content("Text with #{cross_reference}#{mr.to_reference}")
expect(page).to have_content("moved from #{cross_reference}#{issue.to_reference}")
expect(page).to have_content(issue.title)
+ expect(page.current_path).to include project_path(new_project)
end
scenario 'searching project dropdown', js: true do
@@ -66,8 +63,8 @@ feature 'issue move to another project' do
end
context 'user does not have permission to move the issue to a project', js: true do
- let!(:private_project) { create(:project, :private) }
- let(:another_project) { create(:project) }
+ let!(:private_project) { create(:empty_project, :private) }
+ let(:another_project) { create(:empty_project) }
background { another_project.team << [user, :guest] }
scenario 'browsing projects in projects select' do
@@ -98,10 +95,6 @@ feature 'issue move to another project' do
end
def issue_path(issue)
- namespace_project_issue_path(issue.project.namespace, issue.project, issue)
- end
-
- def project_path(project)
- namespace_project_path(new_project.namespace, new_project)
+ project_issue_path(issue.project, issue)
end
end
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
index bd31e44ef33..b524260750e 100644
--- a/spec/features/issues/note_polling_spec.rb
+++ b/spec/features/issues/note_polling_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Issue notes polling', :feature, :js do
+feature 'Issue notes polling', :js do
include NoteInteractionHelpers
let(:project) { create(:empty_project, :public) }
@@ -8,7 +8,7 @@ feature 'Issue notes polling', :feature, :js do
describe 'creates' do
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'displays the new comment' do
@@ -27,8 +27,8 @@ feature 'Issue notes polling', :feature, :js do
let!(:existing_note) { create(:note, noteable: issue, project: project, author: user, note: note_text) }
before do
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
end
it 'has .original-note-content to compare against' do
@@ -93,8 +93,8 @@ feature 'Issue notes polling', :feature, :js do
let!(:existing_note) { create(:note, noteable: issue, project: project, author: user1, note: note_text) }
before do
- gitlab_sign_in(user2)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user2)
+ visit project_issue_path(project, issue)
end
it 'has .original-note-content to compare against' do
@@ -114,8 +114,8 @@ feature 'Issue notes polling', :feature, :js do
let!(:system_note) { create(:system_note, noteable: issue, project: project, author: user, note: note_text) }
before do
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
end
it 'has .original-note-content to compare against' do
diff --git a/spec/features/issues/notes_on_issues_spec.rb b/spec/features/issues/notes_on_issues_spec.rb
index f648295416f..29c9b99030a 100644
--- a/spec/features/issues/notes_on_issues_spec.rb
+++ b/spec/features/issues/notes_on_issues_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Create notes on issues', :js, :feature do
+describe 'Create notes on issues', :js do
let(:user) { create(:user) }
shared_examples 'notes with reference' do
@@ -9,8 +9,8 @@ describe 'Create notes on issues', :js, :feature do
before do
project.team << [user, :developer]
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
fill_in 'note[note]', with: note_text
click_button 'Comment'
@@ -35,42 +35,42 @@ describe 'Create notes on issues', :js, :feature do
context 'mentioning issue on a private project' do
it_behaves_like 'notes with reference' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:empty_project, :private) }
let(:mention) { create(:issue, project: project) }
end
end
context 'mentioning issue on an internal project' do
it_behaves_like 'notes with reference' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:empty_project, :internal) }
let(:mention) { create(:issue, project: project) }
end
end
context 'mentioning issue on a public project' do
it_behaves_like 'notes with reference' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:mention) { create(:issue, project: project) }
end
end
context 'mentioning merge request on a private project' do
it_behaves_like 'notes with reference' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:project, :private, :repository) }
let(:mention) { create(:merge_request, source_project: project) }
end
end
context 'mentioning merge request on an internal project' do
it_behaves_like 'notes with reference' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :internal, :repository) }
let(:mention) { create(:merge_request, source_project: project) }
end
end
context 'mentioning merge request on a public project' do
it_behaves_like 'notes with reference' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:mention) { create(:merge_request, source_project: project) }
end
end
diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb
index 57c783790b5..7a05e8b2ccc 100644
--- a/spec/features/issues/spam_issues_spec.rb
+++ b/spec/features/issues/spam_issues_spec.rb
@@ -1,9 +1,9 @@
require 'rails_helper'
-describe 'New issue', feature: true, js: true do
+describe 'New issue', js: true do
include StubENV
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:user) { create(:user)}
before do
@@ -18,14 +18,14 @@ describe 'New issue', feature: true, js: true do
)
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when identified as a spam' do
before do
WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "true", status: 200)
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
end
it 'creates an issue after solving reCaptcha' do
@@ -50,7 +50,7 @@ describe 'New issue', feature: true, js: true do
before do
WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: 'false', status: 200)
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
end
it 'creates an issue' do
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
index a1c00dd64f6..2460ae817f9 100644
--- a/spec/features/issues/todo_spec.rb
+++ b/spec/features/issues/todo_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-feature 'Manually create a todo item from issue', feature: true, js: true do
- let!(:project) { create(:project) }
- let!(:issue) { create(:issue, project: project) }
- let!(:user) { create(:user)}
+feature 'Manually create a todo item from issue', js: true do
+ let!(:project) { create(:empty_project) }
+ let!(:issue) { create(:issue, project: project) }
+ let!(:user) { create(:user)}
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
end
it 'creates todo when clicking button' do
@@ -21,7 +21,7 @@ feature 'Manually create a todo item from issue', feature: true, js: true do
expect(page).to have_content '1'
end
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
page.within '.header-content .todos-count' do
expect(page).to have_content '1'
@@ -36,7 +36,7 @@ feature 'Manually create a todo item from issue', feature: true, js: true do
expect(page).to have_selector('.todos-count', visible: false)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(page).to have_selector('.todos-count', visible: false)
end
diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb
index dc981406e4e..389151e63f0 100644
--- a/spec/features/issues/update_issues_spec.rb
+++ b/spec/features/issues/update_issues_spec.rb
@@ -1,18 +1,18 @@
require 'rails_helper'
-feature 'Multiple issue updating from issues#index', feature: true do
- let!(:project) { create(:project) }
+feature 'Multiple issue updating from issues#index', :js do
+ let!(:project) { create(:empty_project) }
let!(:issue) { create(:issue, project: project) }
let!(:user) { create(:user)}
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
- context 'status', js: true do
+ context 'status' do
it 'sets to closed' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_button 'Edit Issues'
find('#check-all-issues').click
@@ -25,7 +25,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
it 'sets to open' do
create_closed
- visit namespace_project_issues_path(project.namespace, project, state: 'closed')
+ visit project_issues_path(project, state: 'closed')
click_button 'Edit Issues'
find('#check-all-issues').click
@@ -37,9 +37,9 @@ feature 'Multiple issue updating from issues#index', feature: true do
end
end
- context 'assignee', js: true do
+ context 'assignee' do
it 'updates to current user' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_button 'Edit Issues'
find('#check-all-issues').click
@@ -55,7 +55,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
it 'updates to unassigned' do
create_assigned
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_button 'Edit Issues'
find('#check-all-issues').click
@@ -67,11 +67,11 @@ feature 'Multiple issue updating from issues#index', feature: true do
end
end
- context 'milestone', js: true do
- let(:milestone) { create(:milestone, project: project) }
+ context 'milestone' do
+ let!(:milestone) { create(:milestone, project: project) }
it 'updates milestone' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_button 'Edit Issues'
find('#check-all-issues').click
@@ -85,7 +85,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
it 'sets to no milestone' do
create_with_milestone
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
expect(first('.issue')).to have_content milestone.title
diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index 168cdd08137..d28ad52ff56 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'Issues > User uses quick actions', feature: true, js: true do
+feature 'Issues > User uses quick actions', js: true do
include QuickActionsHelpers
it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do
@@ -9,18 +9,28 @@ feature 'Issues > User uses quick actions', feature: true, js: true do
describe 'issue-only commands' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
end
after do
wait_for_requests
end
+ describe 'time tracking' do
+ let(:issue) { create(:issue, project: project) }
+
+ before do
+ visit project_issue_path(project, issue)
+ end
+
+ it_behaves_like 'issuable time tracker'
+ end
+
describe 'adding a due date from note' do
let(:issue) { create(:issue, project: project) }
@@ -42,8 +52,8 @@ feature 'Issues > User uses quick actions', feature: true, js: true do
before do
project.team << [guest, :guest]
gitlab_sign_out
- gitlab_sign_in(guest)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(guest)
+ visit project_issue_path(project, issue)
end
it 'does not create a note, and sets the due date accordingly' do
@@ -82,8 +92,8 @@ feature 'Issues > User uses quick actions', feature: true, js: true do
before do
project.team << [guest, :guest]
gitlab_sign_out
- gitlab_sign_in(guest)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(guest)
+ visit project_issue_path(project, issue)
end
it 'does not create a note, and sets the due date accordingly' do
@@ -99,65 +109,50 @@ feature 'Issues > User uses quick actions', feature: true, js: true do
end
end
- describe 'Issuable time tracking' do
+ describe 'toggling the WIP prefix from the title from note' do
let(:issue) { create(:issue, project: project) }
- before do
- project.team << [user, :developer]
- end
-
- context 'Issue' do
- before do
- visit namespace_project_issue_path(project.namespace, project, issue)
- end
-
- it_behaves_like 'issuable time tracker'
- end
-
- context 'Merge Request' do
- let(:merge_request) { create(:merge_request, source_project: project) }
-
- before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
- end
+ it 'does not recognize the command nor create a note' do
+ write_note("/wip")
- it_behaves_like 'issuable time tracker'
+ expect(page).not_to have_content '/wip'
end
end
- describe 'Issuable time tracking' do
+ describe 'mark issue as duplicate' do
let(:issue) { create(:issue, project: project) }
+ let(:original_issue) { create(:issue, project: project) }
- before do
- project.team << [user, :developer]
- end
+ context 'when the current user can update issues' do
+ it 'does not create a note, and marks the issue as a duplicate' do
+ write_note("/duplicate ##{original_issue.to_reference}")
- context 'Issue' do
- before do
- visit namespace_project_issue_path(project.namespace, project, issue)
- end
+ expect(page).not_to have_content "/duplicate #{original_issue.to_reference}"
+ expect(page).to have_content 'Commands applied'
+ expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}"
- it_behaves_like 'issuable time tracker'
+ expect(issue.reload).to be_closed
+ end
end
- context 'Merge Request' do
- let(:merge_request) { create(:merge_request, source_project: project) }
-
+ context 'when the current user cannot update the issue' do
+ let(:guest) { create(:user) }
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ project.team << [guest, :guest]
+ gitlab_sign_out
+ sign_in(guest)
+ visit project_issue_path(project, issue)
end
- it_behaves_like 'issuable time tracker'
- end
- end
-
- describe 'toggling the WIP prefix from the title from note' do
- let(:issue) { create(:issue, project: project) }
+ it 'does not create a note, and does not mark the issue as a duplicate' do
+ write_note("/duplicate ##{original_issue.to_reference}")
- it 'does not recognize the command nor create a note' do
- write_note("/wip")
+ expect(page).to have_content "/duplicate ##{original_issue.to_reference}"
+ expect(page).not_to have_content 'Commands applied'
+ expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}"
- expect(page).not_to have_content '/wip'
+ expect(issue.reload).to be_open
+ end
end
end
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 87bd8a08b06..4f4bf189280 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Issues', feature: true do
+describe 'Issues' do
include DropzoneHelper
include IssueHelpers
include SortingHelper
@@ -24,7 +24,7 @@ describe 'Issues', feature: true do
end
before do
- visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ visit edit_project_issue_path(project, issue)
find('.js-zen-enter').click
end
@@ -42,7 +42,7 @@ describe 'Issues', feature: true do
end
it 'allows user to select unassigned', js: true do
- visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ visit edit_project_issue_path(project, issue)
expect(page).to have_content "Assignee #{user.name}"
@@ -62,7 +62,7 @@ describe 'Issues', feature: true do
describe 'due date', js: true do
context 'on new form' do
before do
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
end
it 'saves with due date' do
@@ -90,7 +90,7 @@ describe 'Issues', feature: true do
let(:issue) { create(:issue, author: user, project: project, due_date: Date.today.at_beginning_of_month.to_s) }
before do
- visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ visit edit_project_issue_path(project, issue)
end
it 'saves with due date' do
@@ -135,7 +135,7 @@ describe 'Issues', feature: true do
issue = create(:issue, author: user, assignees: [user], project: project, title: 'foobar')
create(:award_emoji, awardable: issue)
- visit namespace_project_issues_path(project.namespace, project, assignee_id: user.id)
+ visit project_issues_path(project, assignee_id: user.id)
expect(page).to have_content 'foobar'
expect(page.all('.no-comments').first.text).to eq "0"
@@ -161,7 +161,7 @@ describe 'Issues', feature: true do
let(:issue) { @issue }
it 'allows filtering by issues with no specified assignee' do
- visit namespace_project_issues_path(project.namespace, project, assignee_id: IssuableFinder::NONE)
+ visit project_issues_path(project, assignee_id: IssuableFinder::NONE)
expect(page).to have_content 'foobar'
expect(page).not_to have_content 'barbaz'
@@ -169,7 +169,7 @@ describe 'Issues', feature: true do
end
it 'allows filtering by a specified assignee' do
- visit namespace_project_issues_path(project.namespace, project, assignee_id: user.id)
+ visit project_issues_path(project, assignee_id: user.id)
expect(page).not_to have_content 'foobar'
expect(page).to have_content 'barbaz'
@@ -190,14 +190,14 @@ describe 'Issues', feature: true do
let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') }
it 'sorts by newest' do
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_recently_created)
+ visit project_issues_path(project, sort: sort_value_recently_created)
expect(first_issue).to include('foo')
expect(last_issue).to include('baz')
end
it 'sorts by oldest' do
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_oldest_created)
+ visit project_issues_path(project, sort: sort_value_oldest_created)
expect(first_issue).to include('baz')
expect(last_issue).to include('foo')
@@ -206,7 +206,7 @@ describe 'Issues', feature: true do
it 'sorts by most recently updated' do
baz.updated_at = Time.now + 100
baz.save
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_recently_updated)
+ visit project_issues_path(project, sort: sort_value_recently_updated)
expect(first_issue).to include('baz')
end
@@ -214,7 +214,7 @@ describe 'Issues', feature: true do
it 'sorts by least recently updated' do
baz.updated_at = Time.now - 100
baz.save
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_oldest_updated)
+ visit project_issues_path(project, sort: sort_value_oldest_updated)
expect(first_issue).to include('baz')
end
@@ -226,13 +226,13 @@ describe 'Issues', feature: true do
end
it 'sorts by recently due date' do
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_due_date_soon)
+ visit project_issues_path(project, sort: sort_value_due_date_soon)
expect(first_issue).to include('foo')
end
it 'sorts by least recently due date' do
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_due_date_later)
+ visit project_issues_path(project, sort: sort_value_due_date_later)
expect(first_issue).to include('bar')
end
@@ -240,7 +240,7 @@ describe 'Issues', feature: true do
it 'sorts by least recently due date by excluding nil due dates' do
bar.update(due_date: nil)
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_due_date_later)
+ visit project_issues_path(project, sort: sort_value_due_date_later)
expect(first_issue).to include('foo')
end
@@ -255,7 +255,7 @@ describe 'Issues', feature: true do
it 'sorts by least recently due date by excluding nil due dates' do
bar.update(due_date: nil)
- visit namespace_project_issues_path(project.namespace, project, label_names: [label.name], sort: sort_value_due_date_later)
+ visit project_issues_path(project, label_names: [label.name], sort: sort_value_due_date_later)
expect(first_issue).to include('foo')
end
@@ -269,7 +269,7 @@ describe 'Issues', feature: true do
end
it 'filters by none' do
- visit namespace_project_issues_path(project.namespace, project, due_date: Issue::NoDueDate.name)
+ visit project_issues_path(project, due_date: Issue::NoDueDate.name)
expect(page).not_to have_content('foo')
expect(page).not_to have_content('bar')
@@ -277,7 +277,7 @@ describe 'Issues', feature: true do
end
it 'filters by any' do
- visit namespace_project_issues_path(project.namespace, project, due_date: Issue::AnyDueDate.name)
+ visit project_issues_path(project, due_date: Issue::AnyDueDate.name)
expect(page).to have_content('foo')
expect(page).to have_content('bar')
@@ -289,7 +289,7 @@ describe 'Issues', feature: true do
bar.update(due_date: Date.today.end_of_week)
baz.update(due_date: Date.today - 8.days)
- visit namespace_project_issues_path(project.namespace, project, due_date: Issue::DueThisWeek.name)
+ visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
expect(page).to have_content('foo')
expect(page).to have_content('bar')
@@ -301,7 +301,7 @@ describe 'Issues', feature: true do
bar.update(due_date: Date.today.end_of_month)
baz.update(due_date: Date.today - 50.days)
- visit namespace_project_issues_path(project.namespace, project, due_date: Issue::DueThisMonth.name)
+ visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
expect(page).to have_content('foo')
expect(page).to have_content('bar')
@@ -313,7 +313,7 @@ describe 'Issues', feature: true do
bar.update(due_date: Date.today + 20.days)
baz.update(due_date: Date.yesterday)
- visit namespace_project_issues_path(project.namespace, project, due_date: Issue::Overdue.name)
+ visit project_issues_path(project, due_date: Issue::Overdue.name)
expect(page).not_to have_content('foo')
expect(page).not_to have_content('bar')
@@ -330,14 +330,14 @@ describe 'Issues', feature: true do
end
it 'sorts by recently due milestone' do
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_soon)
+ visit project_issues_path(project, sort: sort_value_milestone_soon)
expect(first_issue).to include('foo')
expect(last_issue).to include('baz')
end
it 'sorts by least recently due milestone' do
- visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_later)
+ visit project_issues_path(project, sort: sort_value_milestone_later)
expect(first_issue).to include('bar')
expect(last_issue).to include('baz')
@@ -355,7 +355,7 @@ describe 'Issues', feature: true do
end
it 'sorts with a filter applied' do
- visit namespace_project_issues_path(project.namespace, project,
+ visit project_issues_path(project,
sort: sort_value_oldest_created,
assignee_id: user2.id)
@@ -397,7 +397,7 @@ describe 'Issues', feature: true do
let!(:label) { create(:label, project: project) }
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'will not send ajax request when no data is changed' do
@@ -416,7 +416,7 @@ describe 'Issues', feature: true do
context 'by authorized user' do
it 'allows user to select unassigned', js: true do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
page.within('.assignee') do
expect(page).to have_content "#{user.name}"
@@ -435,7 +435,7 @@ describe 'Issues', feature: true do
it 'allows user to select an assignee', js: true do
issue2 = create(:issue, project: project, author: user)
- visit namespace_project_issue_path(project.namespace, project, issue2)
+ visit project_issue_path(project, issue2)
page.within('.assignee') do
expect(page).to have_content "No assignee"
@@ -456,7 +456,7 @@ describe 'Issues', feature: true do
it 'allows user to unselect themselves', js: true do
issue2 = create(:issue, project: project, author: user)
- visit namespace_project_issue_path(project.namespace, project, issue2)
+ visit project_issue_path(project, issue2)
page.within '.assignee' do
click_link 'Edit'
@@ -487,7 +487,7 @@ describe 'Issues', feature: true do
sign_out(:user)
sign_in(guest)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(page).to have_content issue.assignees.first.name
end
end
@@ -499,7 +499,7 @@ describe 'Issues', feature: true do
context 'by authorized user' do
it 'allows user to select unassigned', js: true do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
page.within('.milestone') do
expect(page).to have_content "None"
@@ -517,7 +517,7 @@ describe 'Issues', feature: true do
end
it 'allows user to de-select milestone', js: true do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
page.within('.milestone') do
click_link 'Edit'
@@ -550,7 +550,7 @@ describe 'Issues', feature: true do
sign_out(:user)
sign_in(guest)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(page).to have_content milestone.title
end
end
@@ -565,23 +565,21 @@ describe 'Issues', feature: true do
end
it 'redirects to signin then back to new issue after signin' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_link 'New issue'
expect(current_path).to eq new_user_session_path
- # NOTE: This is specifically testing the redirect after login, so we
- # need the full login flow
gitlab_sign_in(create(:user))
- expect(current_path).to eq new_namespace_project_issue_path(project.namespace, project)
+ expect(current_path).to eq new_project_issue_path(project)
end
end
context 'dropzone upload file', js: true do
before do
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
end
it 'uploads file when dragging into textarea' do
@@ -608,7 +606,7 @@ describe 'Issues', feature: true do
message: 'added issue template',
branch_name: 'master')
- visit new_namespace_project_issue_path(project.namespace, project, issuable_template: 'bug')
+ visit new_project_issue_path(project, issuable_template: 'bug')
end
it 'fills in template' do
@@ -625,7 +623,7 @@ describe 'Issues', feature: true do
project.issues << issue
stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
click_button('Email a new issue')
end
@@ -654,7 +652,7 @@ describe 'Issues', feature: true do
let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
before do
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'adds due date to issue' do
@@ -698,7 +696,7 @@ describe 'Issues', feature: true do
it 'updates the title', js: true do
issue = create(:issue, author: user, assignees: [user], project: project, title: 'new title')
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
expect(page).to have_text("new title")
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index 53b8ba5b0f7..c9983f0941f 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Login', feature: true do
+feature 'Login' do
describe 'initial login after setup' do
it 'allows the initial admin to create a password' do
# This behavior is dependent on there only being one user
@@ -41,7 +41,7 @@ feature 'Login', feature: true do
expect(page).to have_content('Your account has been blocked.')
end
- it 'does not update Devise trackable attributes', :redis do
+ it 'does not update Devise trackable attributes', :clean_gitlab_redis_shared_state do
user = create(:user, :blocked)
expect { gitlab_sign_in(user) }.not_to change { user.reload.sign_in_count }
@@ -55,7 +55,7 @@ feature 'Login', feature: true do
expect(page).to have_content('Invalid Login or password.')
end
- it 'does not update Devise trackable attributes', :redis do
+ it 'does not update Devise trackable attributes', :clean_gitlab_redis_shared_state do
expect { gitlab_sign_in(User.ghost) }.not_to change { User.ghost.reload.sign_in_count }
end
end
@@ -143,29 +143,8 @@ feature 'Login', feature: true do
end
context 'logging in via OAuth' do
- def saml_config
- OpenStruct.new(name: 'saml', label: 'saml', args: {
- assertion_consumer_service_url: 'https://localhost:3443/users/auth/saml/callback',
- idp_cert_fingerprint: '26:43:2C:47:AF:F0:6B:D0:07:9C:AD:A3:74:FE:5D:94:5F:4E:9E:52',
- idp_sso_target_url: 'https://idp.example.com/sso/saml',
- issuer: 'https://localhost:3443/',
- name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
- })
- end
-
- def stub_omniauth_config(messages)
- Rails.application.env_config['devise.mapping'] = Devise.mappings[:user]
- Rails.application.routes.disable_clear_and_finalize = true
- Rails.application.routes.draw do
- post '/users/auth/saml' => 'omniauth_callbacks#saml'
- end
- allow(Gitlab::OAuth::Provider).to receive_messages(providers: [:saml], config_for: saml_config)
- allow(Gitlab.config.omniauth).to receive_messages(messages)
- expect_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml')
- end
-
it 'shows 2FA prompt after OAuth login' do
- stub_omniauth_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [saml_config])
+ stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config])
user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml')
gitlab_sign_in_via('saml', user, 'my-uid')
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 534be3ab5a7..b70d3060f05 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -24,7 +24,7 @@ require 'erb'
#
# See the MarkdownFeature class for setup details.
-describe 'GitLab Markdown', feature: true do
+describe 'GitLab Markdown' do
include Capybara::Node::Matchers
include MarkupHelper
include MarkdownMatchers
@@ -100,7 +100,7 @@ describe 'GitLab Markdown', feature: true do
end
it 'permits img elements' do
- expect(doc).to have_selector('img[src*="smile.png"]')
+ expect(doc).to have_selector('img[data-src*="smile.png"]')
end
it 'permits br elements' do
diff --git a/spec/features/merge_requests/assign_issues_spec.rb b/spec/features/merge_requests/assign_issues_spec.rb
index cb835f533e0..63fa72650ac 100644
--- a/spec/features/merge_requests/assign_issues_spec.rb
+++ b/spec/features/merge_requests/assign_issues_spec.rb
@@ -1,8 +1,8 @@
require 'rails_helper'
-feature 'Merge request issue assignment', js: true, feature: true do
+feature 'Merge request issue assignment', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user, description: "fixes #{issue1.to_reference} and #{issue2.to_reference}") }
@@ -13,8 +13,8 @@ feature 'Merge request issue assignment', js: true, feature: true do
end
def visit_merge_request(current_user = nil)
- gitlab_sign_in(current_user || user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(current_user || user)
+ visit project_merge_request_path(project, merge_request)
end
context 'logged in as author' do
diff --git a/spec/features/merge_requests/award_spec.rb b/spec/features/merge_requests/award_spec.rb
index e9dd755b6af..e886309133d 100644
--- a/spec/features/merge_requests/award_spec.rb
+++ b/spec/features/merge_requests/award_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-feature 'Merge request awards', js: true, feature: true do
+feature 'Merge request awards', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
describe 'logged in' do
before do
- gitlab_sign_in(user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
end
it 'adds award to merge request' do
@@ -16,7 +16,7 @@ feature 'Merge request awards', js: true, feature: true do
expect(page).to have_selector('.js-emoji-btn.active')
expect(first('.js-emoji-btn')).to have_content '1'
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
expect(first('.js-emoji-btn')).to have_content '1'
end
@@ -25,7 +25,7 @@ feature 'Merge request awards', js: true, feature: true do
find('.js-emoji-btn.active').click
expect(first('.js-emoji-btn')).to have_content '0'
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
expect(first('.js-emoji-btn')).to have_content '0'
end
@@ -39,7 +39,7 @@ feature 'Merge request awards', js: true, feature: true do
describe 'logged out' do
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not see award menu button' do
diff --git a/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb b/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb
index 060cfb8fdd1..1f5e7b55fb0 100644
--- a/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb
+++ b/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Check if mergeable with unresolved discussions', js: true, feature: true do
+feature 'Check if mergeable with unresolved discussions', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let!(:merge_request) { create(:merge_request_with_diff_notes, source_project: project, author: user) }
before do
- gitlab_sign_in user
+ sign_in user
project.team << [user, :master]
end
@@ -64,6 +64,6 @@ feature 'Check if mergeable with unresolved discussions', js: true, feature: tru
end
def visit_merge_request(merge_request)
- visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ visit project_merge_request_path(merge_request.project, merge_request)
end
end
diff --git a/spec/features/merge_requests/cherry_pick_spec.rb b/spec/features/merge_requests/cherry_pick_spec.rb
index 6ba96570e3d..4b1e1b9a8d4 100644
--- a/spec/features/merge_requests/cherry_pick_spec.rb
+++ b/spec/features/merge_requests/cherry_pick_spec.rb
@@ -3,11 +3,11 @@ require 'spec_helper'
describe 'Cherry-pick Merge Requests', js: true do
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:project, :repository, namespace: group) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user) }
before do
- gitlab_sign_in user
+ sign_in user
project.team << [user, :master]
end
@@ -28,7 +28,7 @@ describe 'Cherry-pick Merge Requests', js: true do
end
it "doesn't show a Cherry-pick button" do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
expect(page).not_to have_link "Cherry-pick"
end
@@ -36,7 +36,7 @@ describe 'Cherry-pick Merge Requests', js: true do
context "With a merge commit" do
it "shows a Cherry-pick button" do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
expect(page).to have_link "Cherry-pick"
end
diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb
index 365b2555c35..0e97254eada 100644
--- a/spec/features/merge_requests/closes_issues_spec.rb
+++ b/spec/features/merge_requests/closes_issues_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Merge Request closing issues message', feature: true, js: true do
+feature 'Merge Request closing issues message', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:issue_1) { create(:issue, project: project)}
let(:issue_2) { create(:issue, project: project)}
let(:merge_request) do
@@ -20,9 +20,9 @@ feature 'Merge Request closing issues message', feature: true, js: true do
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
wait_for_requests
end
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index 830ec6cb9fc..19a38afb410 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -1,8 +1,13 @@
require 'spec_helper'
-feature 'Merge request conflict resolution', js: true, feature: true do
+feature 'Merge request conflict resolution', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
+
+ before do
+ # In order to have the diffs collapsed, we need to disable the increase feature
+ stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
+ end
def create_merge_request(source_branch)
create(:merge_request, source_branch: source_branch, target_branch: 'conflict-start', source_project: project) do |mr|
@@ -79,14 +84,14 @@ feature 'Merge request conflict resolution', js: true, feature: true do
context 'can be resolved in the UI' do
before do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'the conflicts are resolvable' do
let(:merge_request) { create_merge_request('conflict-resolvable') }
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'shows a link to the conflict resolution page' do
@@ -117,7 +122,7 @@ feature 'Merge request conflict resolution', js: true, feature: true do
let(:merge_request) { create_merge_request('conflict-contains-conflict-markers') }
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
click_link('conflicts', href: /\/conflicts\Z/)
end
@@ -164,9 +169,9 @@ feature 'Merge request conflict resolution', js: true, feature: true do
before do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not show a link to the conflict resolution page' do
diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb
index 8f7adbccaaa..11a74276898 100644
--- a/spec/features/merge_requests/create_new_mr_spec.rb
+++ b/spec/features/merge_requests/create_new_mr_spec.rb
@@ -1,17 +1,17 @@
require 'spec_helper'
-feature 'Create New Merge Request', feature: true, js: true do
+feature 'Create New Merge Request', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
it 'selects the source branch sha when a tag with the same name exists' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
click_link 'New merge request'
expect(page).to have_content('Source branch')
@@ -24,7 +24,7 @@ feature 'Create New Merge Request', feature: true, js: true do
end
it 'selects the target branch sha when a tag with the same name exists' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
click_link 'New merge request'
@@ -38,7 +38,7 @@ feature 'Create New Merge Request', feature: true, js: true do
end
it 'generates a diff for an orphaned branch' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
expect(page).to have_content('Source branch')
@@ -63,9 +63,9 @@ feature 'Create New Merge Request', feature: true, js: true do
context 'when target project cannot be viewed by the current user' do
it 'does not leak the private project name & namespace' do
- private_project = create(:project, :private)
+ private_project = create(:project, :private, :repository)
- visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_project_id: private_project.id })
+ visit project_new_merge_request_path(project, merge_request: { target_project_id: private_project.id })
expect(page).not_to have_content private_project.path_with_namespace
expect(page).to have_content project.path_with_namespace
@@ -74,9 +74,9 @@ feature 'Create New Merge Request', feature: true, js: true do
context 'when source project cannot be viewed by the current user' do
it 'does not leak the private project name & namespace' do
- private_project = create(:project, :private)
+ private_project = create(:project, :private, :repository)
- visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { source_project_id: private_project.id })
+ visit project_new_merge_request_path(project, merge_request: { source_project_id: private_project.id })
expect(page).not_to have_content private_project.path_with_namespace
expect(page).to have_content project.path_with_namespace
@@ -84,13 +84,13 @@ feature 'Create New Merge Request', feature: true, js: true do
end
it 'populates source branch button' do
- visit new_namespace_project_merge_request_path(project.namespace, project, change_branches: true, merge_request: { target_branch: 'master', source_branch: 'fix' })
+ visit project_new_merge_request_path(project, change_branches: true, merge_request: { target_branch: 'master', source_branch: 'fix' })
expect(find('.js-source-branch')).to have_content('fix')
end
it 'allows to change the diff view' do
- visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'fix' })
+ visit project_new_merge_request_path(project, merge_request: { target_branch: 'master', source_branch: 'fix' })
click_link 'Changes'
@@ -106,7 +106,7 @@ feature 'Create New Merge Request', feature: true, js: true do
end
it 'does not allow non-existing branches' do
- visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'non-exist-target', source_branch: 'non-exist-source' })
+ visit project_new_merge_request_path(project, merge_request: { target_branch: 'non-exist-target', source_branch: 'non-exist-source' })
expect(page).to have_content('The form contains the following errors')
expect(page).to have_content('Source branch "non-exist-source" does not exist')
@@ -115,7 +115,7 @@ feature 'Create New Merge Request', feature: true, js: true do
context 'when a branch contains commits that both delete and add the same image' do
it 'renders the diff successfully' do
- visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'master', source_branch: 'deleted-image-test' })
+ visit project_new_merge_request_path(project, merge_request: { target_branch: 'master', source_branch: 'deleted-image-test' })
click_link "Changes"
@@ -125,7 +125,7 @@ feature 'Create New Merge Request', feature: true, js: true do
# Isolates a regression (see #24627)
it 'does not show error messages on initial form' do
- visit new_namespace_project_merge_request_path(project.namespace, project)
+ visit project_new_merge_request_path(project)
expect(page).not_to have_selector('#error_explanation')
expect(page).not_to have_content('The form contains the following error')
end
@@ -138,8 +138,8 @@ feature 'Create New Merge Request', feature: true, js: true do
end
it 'shows pipelines for a new merge request' do
- visit new_namespace_project_merge_request_path(
- project.namespace, project,
+ visit project_new_merge_request_path(
+ project,
merge_request: { target_branch: 'master', source_branch: 'fix' })
page.within('.merge-request') do
diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb
index 69059dfa562..09541873f71 100644
--- a/spec/features/merge_requests/created_from_fork_spec.rb
+++ b/spec/features/merge_requests/created_from_fork_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
feature 'Merge request created from fork' do
given(:user) { create(:user) }
- given(:project) { create(:project, :public) }
- given(:fork_project) { create(:project, :public) }
+ given(:project) { create(:project, :public, :repository) }
+ given(:fork_project) { create(:project, :public, :repository) }
given!(:merge_request) do
create(:forked_project_link, forked_to_project: fork_project,
@@ -16,7 +16,7 @@ feature 'Merge request created from fork' do
background do
fork_project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
scenario 'user can access merge request' do
@@ -25,6 +25,33 @@ feature 'Merge request created from fork' do
expect(page).to have_content 'Test merge request'
end
+ context 'when a commit comment exists on the merge request' do
+ given(:comment) { 'A commit comment' }
+ given(:reply) { 'A reply comment' }
+
+ background do
+ create(:note_on_commit, note: comment,
+ project: fork_project,
+ commit_id: merge_request.commit_shas.first)
+ end
+
+ scenario 'user can reply to the comment', js: true do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_content(comment)
+
+ page.within('.discussion-notes') do
+ find('.btn-text-field').click
+ find('#note_note').send_keys(reply)
+ find('.comment-btn').click
+ end
+
+ wait_for_requests
+
+ expect(page).to have_content(reply)
+ end
+ end
+
context 'source project is deleted' do
background do
MergeRequests::MergeService.new(project, user).execute(merge_request)
@@ -64,7 +91,6 @@ feature 'Merge request created from fork' do
end
def visit_merge_request(mr)
- visit namespace_project_merge_request_path(project.namespace,
- project, mr)
+ visit project_merge_request_path(project, mr)
end
end
diff --git a/spec/features/merge_requests/deleted_source_branch_spec.rb b/spec/features/merge_requests/deleted_source_branch_spec.rb
index f2af3198319..874c6e2ff69 100644
--- a/spec/features/merge_requests/deleted_source_branch_spec.rb
+++ b/spec/features/merge_requests/deleted_source_branch_spec.rb
@@ -3,19 +3,15 @@ require 'spec_helper'
# This test serves as a regression test for a bug that caused an error
# message to be shown by JavaScript when the source branch was deleted.
# Please do not remove "js: true".
-describe 'Deleted source branch', feature: true, js: true do
+describe 'Deleted source branch', js: true do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
before do
- gitlab_sign_in user
+ sign_in user
merge_request.project.team << [user, :master]
merge_request.update!(source_branch: 'this-branch-does-not-exist')
- visit namespace_project_merge_request_path(
- merge_request.project.namespace,
- merge_request.project,
- merge_request
- )
+ visit project_merge_request_path(merge_request.project, merge_request)
end
it 'shows a message about missing source branch' do
diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb
index f63214efa03..737045413bf 100644
--- a/spec/features/merge_requests/diff_notes_avatars_spec.rb
+++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Diff note avatars', feature: true, js: true do
+feature 'Diff note avatars', js: true do
include NoteInteractionHelpers
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
let(:path) { "files/ruby/popen.rb" }
let(:position) do
@@ -20,12 +20,12 @@ feature 'Diff note avatars', feature: true, js: true do
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'discussion tab' do
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not show avatars on discussion tab' do
@@ -50,7 +50,7 @@ feature 'Diff note avatars', feature: true, js: true do
context 'commit view' do
before do
- visit namespace_project_commit_path(project.namespace, project, merge_request.commits.first.id)
+ visit project_commit_path(project, merge_request.commits.first.id)
end
it 'does not render avatar after commenting' do
@@ -65,7 +65,7 @@ feature 'Diff note avatars', feature: true, js: true do
wait_for_requests
end
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
expect(page).to have_content('test comment')
expect(page).not_to have_selector('.js-avatar-container')
@@ -76,7 +76,7 @@ feature 'Diff note avatars', feature: true, js: true do
%w(inline parallel).each do |view|
context "#{view} view" do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: view)
+ visit diffs_project_merge_request_path(project, merge_request, view: view)
wait_for_requests
end
@@ -168,7 +168,7 @@ feature 'Diff note avatars', feature: true, js: true do
before do
create_list(:diff_note_on_merge_request, 3, project: project, noteable: merge_request, in_reply_to: note)
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: view)
+ visit diffs_project_merge_request_path(project, merge_request, view: view)
wait_for_requests
end
diff --git a/spec/features/merge_requests/diff_notes_resolve_spec.rb b/spec/features/merge_requests/diff_notes_resolve_spec.rb
index 766255b018f..5019ed43496 100644
--- a/spec/features/merge_requests/diff_notes_resolve_spec.rb
+++ b/spec/features/merge_requests/diff_notes_resolve_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Diff notes resolve', feature: true, js: true do
+feature 'Diff notes resolve', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) }
let(:path) { "files/ruby/popen.rb" }
@@ -19,7 +19,7 @@ feature 'Diff notes resolve', feature: true, js: true do
context 'no discussions' do
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
note.destroy
visit_merge_request
end
@@ -33,7 +33,7 @@ feature 'Diff notes resolve', feature: true, js: true do
context 'as authorized user' do
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
visit_merge_request
end
@@ -402,7 +402,7 @@ feature 'Diff notes resolve', feature: true, js: true do
before do
project.team << [guest, :guest]
- gitlab_sign_in guest
+ sign_in guest
end
context 'someone elses merge request' do
@@ -494,6 +494,6 @@ feature 'Diff notes resolve', feature: true, js: true do
def visit_merge_request(mr = nil)
mr = mr || merge_request
- visit namespace_project_merge_request_path(mr.project.namespace, mr.project, mr)
+ visit project_merge_request_path(mr.project, mr)
end
end
diff --git a/spec/features/merge_requests/diffs_spec.rb b/spec/features/merge_requests/diffs_spec.rb
index cb6cd6571a8..201be4b9e40 100644
--- a/spec/features/merge_requests/diffs_spec.rb
+++ b/spec/features/merge_requests/diffs_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-feature 'Diffs URL', js: true, feature: true do
- let(:project) { create(:project, :public) }
+feature 'Diffs URL', js: true do
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
context 'when visit with */* as accept header' do
@@ -12,7 +12,7 @@ feature 'Diffs URL', js: true, feature: true do
it 'renders the notes' do
create :note_on_merge_request, project: project, noteable: merge_request, note: 'Rebasing with master'
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit diffs_project_merge_request_path(project, merge_request)
# Load notes and diff through AJAX
expect(page).to have_css('.note-text', visible: false, text: 'Rebasing with master')
@@ -26,7 +26,7 @@ feature 'Diffs URL', js: true, feature: true do
let(:fragment) { "#note_#{note.id}" }
before do
- visit "#{diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)}#{fragment}"
+ visit "#{diffs_project_merge_request_path(project, merge_request)}#{fragment}"
end
it 'shows expanded note' do
@@ -39,7 +39,7 @@ feature 'Diffs URL', js: true, feature: true do
let(:fragment) { "#note_#{note.id}" }
before do
- visit "#{diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)}#{fragment}"
+ visit "#{diffs_project_merge_request_path(project, merge_request)}#{fragment}"
end
it 'shows expanded note' do
@@ -52,7 +52,7 @@ feature 'Diffs URL', js: true, feature: true do
it 'displays warning' do
allow(Commit).to receive(:max_diff_options).and_return(max_files: 3)
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit diffs_project_merge_request_path(project, merge_request)
page.within('.alert') do
expect(page).to have_text("Too many changes to show. Plain diff Email patch To preserve
@@ -74,8 +74,8 @@ feature 'Diffs URL', js: true, feature: true do
context 'as author' do
it 'shows direct edit link' do
- gitlab_sign_in(author_user)
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(author_user)
+ visit diffs_project_merge_request_path(project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
expect(page).to have_selector("[id=\"#{changelog_id}\"] a.js-edit-blob")
@@ -84,8 +84,8 @@ feature 'Diffs URL', js: true, feature: true do
context 'as user who needs to fork' do
it 'shows fork/cancel confirmation' do
- gitlab_sign_in(user)
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(user)
+ visit diffs_project_merge_request_path(project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
find("[id=\"#{changelog_id}\"] .js-edit-blob").click
diff --git a/spec/features/merge_requests/discussion_spec.rb b/spec/features/merge_requests/discussion_spec.rb
index 88ae257236c..d1cc43e0690 100644
--- a/spec/features/merge_requests/discussion_spec.rb
+++ b/spec/features/merge_requests/discussion_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Merge Request Discussions', feature: true do
+feature 'Merge Request Discussions' do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
end
describe "Diff discussions" do
@@ -27,13 +27,13 @@ feature 'Merge Request Discussions', feature: true do
let(:outdated_diff_refs) { project.commit("874797c3a73b60d2187ed6e2fcabd289ff75171e").diff_refs }
before(:each) do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
context 'active discussions' do
it 'shows a link to the diff' do
within(".discussion[data-discussion-id='#{active_discussion.id}']") do
- path = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: active_discussion.line_code)
+ path = diffs_project_merge_request_path(project, merge_request, anchor: active_discussion.line_code)
expect(page).to have_link('the diff', href: path)
end
end
@@ -42,7 +42,7 @@ feature 'Merge Request Discussions', feature: true do
context 'outdated discussions' do
it 'shows a link to the outdated diff' do
within(".discussion[data-discussion-id='#{outdated_discussion.id}']") do
- path = diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, diff_id: old_merge_request_diff.id, anchor: outdated_discussion.line_code)
+ path = diffs_project_merge_request_path(project, merge_request, diff_id: old_merge_request_diff.id, anchor: outdated_discussion.line_code)
expect(page).to have_link('an old version of the diff', href: path)
end
end
@@ -72,7 +72,7 @@ feature 'Merge Request Discussions', feature: true do
end
before(:each) do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
context 'a regular commit comment' do
diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb
index 804bf6967d6..7386e78fb13 100644
--- a/spec/features/merge_requests/edit_mr_spec.rb
+++ b/spec/features/merge_requests/edit_mr_spec.rb
@@ -1,16 +1,16 @@
require 'spec_helper'
-feature 'Edit Merge Request', feature: true do
+feature 'Edit Merge Request' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, :simple, source_project: project) }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
- visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit edit_project_merge_request_path(project, merge_request)
end
context 'editing a MR' do
@@ -33,7 +33,7 @@ feature 'Edit Merge Request', feature: true do
merge_request.update(merge_params: { 'force_remove_source_branch' => '1' })
expect(merge_request.merge_params['force_remove_source_branch']).to be_truthy
- visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit edit_project_merge_request_path(project, merge_request)
uncheck 'Remove source branch when merge request is accepted'
click_button 'Save changes'
diff --git a/spec/features/merge_requests/filter_by_labels_spec.rb b/spec/features/merge_requests/filter_by_labels_spec.rb
index 9b677aeca0a..1d52a4659ad 100644
--- a/spec/features/merge_requests/filter_by_labels_spec.rb
+++ b/spec/features/merge_requests/filter_by_labels_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-feature 'Issue filtering by Labels', feature: true, js: true do
+feature 'Merge Request filtering by Labels', js: true do
include FilteredSearchHelpers
include MergeRequestHelpers
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user) }
let!(:label) { create(:label, project: project) }
@@ -26,9 +26,9 @@ feature 'Issue filtering by Labels', feature: true, js: true do
mr3.labels << feature
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
context 'filter by label bug' do
diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb
index 79bca0c9de2..521fcabc881 100644
--- a/spec/features/merge_requests/filter_by_milestone_spec.rb
+++ b/spec/features/merge_requests/filter_by_milestone_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-feature 'Merge Request filtering by Milestone', feature: true do
+feature 'Merge Request filtering by Milestone' do
include FilteredSearchHelpers
include MergeRequestHelpers
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user)}
let(:milestone) { create(:milestone, project: project) }
@@ -15,7 +15,7 @@ feature 'Merge Request filtering by Milestone', feature: true do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'filters by no Milestone', js: true do
diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb
index c12edf1fdf3..f0019be86ad 100644
--- a/spec/features/merge_requests/filter_merge_requests_spec.rb
+++ b/spec/features/merge_requests/filter_merge_requests_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-describe 'Filter merge requests', feature: true do
+describe 'Filter merge requests' do
include FilteredSearchHelpers
include MergeRequestHelpers
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let!(:group) { create(:group) }
let!(:user) { create(:user) }
let!(:milestone) { create(:milestone, project: project) }
@@ -14,10 +14,10 @@ describe 'Filter merge requests', feature: true do
before do
project.team << [user, :master]
group.add_developer(user)
- gitlab_sign_in(user)
+ sign_in(user)
create(:merge_request, source_project: project, target_project: project)
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
describe 'for assignee from mr#index' do
@@ -132,19 +132,13 @@ describe 'Filter merge requests', feature: true do
end
end
- describe 'for assignee and label from issues#index' do
+ describe 'for assignee and label from mr#index' do
let(:search_query) { "assignee:@#{user.username} label:~#{label.title}" }
before do
- input_filtered_search("assignee:@#{user.username}")
-
- expect_mr_list_count(1)
- expect_tokens([{ name: 'assignee', value: "@#{user.username}" }])
- expect_filtered_search_input_empty
-
- input_filtered_search_keys("label:~#{label.title}")
+ input_filtered_search(search_query)
- expect_mr_list_count(1)
+ expect_mr_list_count(0)
end
context 'assignee and label', js: true do
@@ -191,7 +185,7 @@ describe 'Filter merge requests', feature: true do
assignee: user)
mr.labels << bug_label
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
context 'only text', js: true do
@@ -275,7 +269,7 @@ describe 'Filter merge requests', feature: true do
mr1.labels << bug_label
mr2.labels << bug_label
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it 'is able to filter and sort merge requests' do
@@ -297,7 +291,7 @@ describe 'Filter merge requests', feature: true do
describe 'filter by assignee id', js: true do
it 'filter by current user' do
- visit namespace_project_merge_requests_path(project.namespace, project, assignee_id: user.id)
+ visit project_merge_requests_path(project, assignee_id: user.id)
expect_tokens([{ name: 'assignee', value: "@#{user.username}" }])
expect_filtered_search_input_empty
@@ -307,7 +301,7 @@ describe 'Filter merge requests', feature: true do
new_user = create(:user)
project.add_developer(new_user)
- visit namespace_project_merge_requests_path(project.namespace, project, assignee_id: new_user.id)
+ visit project_merge_requests_path(project, assignee_id: new_user.id)
expect_tokens([{ name: 'assignee', value: "@#{new_user.username}" }])
expect_filtered_search_input_empty
@@ -316,7 +310,7 @@ describe 'Filter merge requests', feature: true do
describe 'filter by author id', js: true do
it 'filter by current user' do
- visit namespace_project_merge_requests_path(project.namespace, project, author_id: user.id)
+ visit project_merge_requests_path(project, author_id: user.id)
expect_tokens([{ name: 'author', value: "@#{user.username}" }])
expect_filtered_search_input_empty
@@ -326,7 +320,7 @@ describe 'Filter merge requests', feature: true do
new_user = create(:user)
project.add_developer(new_user)
- visit namespace_project_merge_requests_path(project.namespace, project, author_id: new_user.id)
+ visit project_merge_requests_path(project, author_id: new_user.id)
expect_tokens([{ name: 'author', value: "@#{new_user.username}" }])
expect_filtered_search_input_empty
diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb
index 1996c2fa09a..6ffb05c5030 100644
--- a/spec/features/merge_requests/form_spec.rb
+++ b/spec/features/merge_requests/form_spec.rb
@@ -1,15 +1,13 @@
require 'rails_helper'
-describe 'New/edit merge request', feature: true, js: true do
- include GitlabRoutingHelper
-
- let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:fork_project) { create(:project, forked_from_project: project) }
- let!(:user) { create(:user)}
- let!(:user2) { create(:user)}
- let!(:milestone) { create(:milestone, project: project) }
- let!(:label) { create(:label, project: project) }
- let!(:label2) { create(:label, project: project) }
+describe 'New/edit merge request', :js do
+ let!(:project) { create(:project, :public, :repository) }
+ let(:fork_project) { create(:project, :repository, forked_from_project: project) }
+ let!(:user) { create(:user) }
+ let!(:user2) { create(:user) }
+ let!(:milestone) { create(:milestone, project: project) }
+ let!(:label) { create(:label, project: project) }
+ let!(:label2) { create(:label, project: project) }
before do
project.team << [user, :master]
@@ -18,13 +16,12 @@ describe 'New/edit merge request', feature: true, js: true do
context 'owned projects' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'new merge request' do
before do
- visit new_namespace_project_merge_request_path(
- project.namespace,
+ visit project_new_merge_request_path(
project,
merge_request: {
source_project_id: project.id,
@@ -114,7 +111,7 @@ describe 'New/edit merge request', feature: true, js: true do
target_branch: 'master'
)
- visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit edit_project_merge_request_path(project, merge_request)
end
it 'updates merge request' do
@@ -177,13 +174,12 @@ describe 'New/edit merge request', feature: true, js: true do
context 'forked project' do
before do
fork_project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'new merge request' do
before do
- visit new_namespace_project_merge_request_path(
- fork_project.namespace,
+ visit project_new_merge_request_path(
fork_project,
merge_request: {
source_project_id: fork_project.id,
@@ -251,7 +247,7 @@ describe 'New/edit merge request', feature: true, js: true do
target_branch: 'master'
)
- visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit edit_project_merge_request_path(project, merge_request)
end
it 'should update merge request' do
diff --git a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb
index 27ba380b005..429bc277d73 100644
--- a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb
+++ b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Clicking toggle commit message link', feature: true, js: true do
+feature 'Clicking toggle commit message link', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:issue_1) { create(:issue, project: project)}
let(:issue_2) { create(:issue, project: project)}
let(:merge_request) do
@@ -34,9 +34,9 @@ feature 'Clicking toggle commit message link', feature: true, js: true do
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
expect(page).not_to have_selector('.js-commit-message')
click_button "Modify commit message"
diff --git a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
index 8af7d985036..0b5a595acce 100644
--- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
+++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Merge immediately', :feature, :js do
+feature 'Merge immediately', :js do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let!(:merge_request) do
create(:merge_request_with_diffs, source_project: project,
@@ -28,8 +28,8 @@ feature 'Merge immediately', :feature, :js do
end
before do
- gitlab_sign_in user
- visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ sign_in user
+ visit project_merge_request_path(merge_request.project, merge_request)
end
it 'enables merge immediately' do
diff --git a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb
index bfadd7cb81a..574f5fe353e 100644
--- a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Merge When Pipeline Succeeds', :feature, :js do
+feature 'Merge When Pipeline Succeeds', :js do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) do
create(:merge_request_with_diffs, source_project: project,
@@ -28,7 +28,7 @@ feature 'Merge When Pipeline Succeeds', :feature, :js do
end
before do
- gitlab_sign_in user
+ sign_in user
visit_merge_request(merge_request)
end
@@ -121,7 +121,7 @@ feature 'Merge When Pipeline Succeeds', :feature, :js do
end
before do
- gitlab_sign_in user
+ sign_in user
visit_merge_request(merge_request)
end
@@ -155,6 +155,6 @@ feature 'Merge When Pipeline Succeeds', :feature, :js do
end
def visit_merge_request(merge_request)
- visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ visit project_merge_request_path(merge_request.project, merge_request)
end
end
diff --git a/spec/features/merge_requests/mini_pipeline_graph_spec.rb b/spec/features/merge_requests/mini_pipeline_graph_spec.rb
index 498b6753519..24abebb3995 100644
--- a/spec/features/merge_requests/mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_requests/mini_pipeline_graph_spec.rb
@@ -1,8 +1,8 @@
require 'rails_helper'
-feature 'Mini Pipeline Graph', :js, :feature do
+feature 'Mini Pipeline Graph', :js do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project, head_pipeline: pipeline) }
let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running', sha: project.commit.id) }
@@ -11,12 +11,12 @@ feature 'Mini Pipeline Graph', :js, :feature do
before do
build.run
- gitlab_sign_in(user)
+ sign_in(user)
visit_merge_request
end
def visit_merge_request(format = :html)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request, format: format)
+ visit project_merge_request_path(project, merge_request, format: format)
end
it 'should display a mini pipeline graph' do
@@ -111,7 +111,7 @@ feature 'Mini Pipeline Graph', :js, :feature do
build_item.click
find('.build-page')
- expect(current_path).to eql(namespace_project_job_path(project.namespace, project, build))
+ expect(current_path).to eql(project_job_path(project, build))
end
it 'should show tooltip when hovered' do
diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb
index 5cd9a7fbe26..5c6eec44ff7 100644
--- a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Only allow merge requests to be merged if the pipeline succeeds', feature: true, js: true do
+feature 'Only allow merge requests to be merged if the pipeline succeeds', js: true do
let(:merge_request) { create(:merge_request_with_diffs) }
let(:project) { merge_request.target_project }
before do
- gitlab_sign_in merge_request.author
+ sign_in merge_request.author
project.team << [merge_request.author, :master]
end
@@ -145,6 +145,6 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', featu
end
def visit_merge_request(merge_request)
- visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ visit project_merge_request_path(merge_request.project, merge_request)
end
end
diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb
index c2241317e04..b3d6cf8deb4 100644
--- a/spec/features/merge_requests/pipelines_spec.rb
+++ b/spec/features/merge_requests/pipelines_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Pipelines for Merge Requests', feature: true, js: true do
+feature 'Pipelines for Merge Requests', js: true do
given(:user) { create(:user) }
given(:merge_request) { create(:merge_request) }
given(:project) { merge_request.target_project }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'with pipelines' do
@@ -19,7 +19,7 @@ feature 'Pipelines for Merge Requests', feature: true, js: true do
end
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
scenario 'user visits merge request pipelines tab' do
@@ -34,7 +34,7 @@ feature 'Pipelines for Merge Requests', feature: true, js: true do
context 'without pipelines' do
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
scenario 'user visits merge request page' do
diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb
index 275f81f50dc..c1b90e5f875 100644
--- a/spec/features/merge_requests/reset_filters_spec.rb
+++ b/spec/features/merge_requests/reset_filters_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'Merge requests filter clear button', feature: true, js: true do
+feature 'Merge requests filter clear button', js: true do
include FilteredSearchHelpers
include MergeRequestHelpers
include IssueHelpers
- let!(:project) { create(:project, :public) }
+ let!(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user) }
let!(:milestone) { create(:milestone, project: project) }
let!(:bug) { create(:label, project: project, name: 'bug')}
diff --git a/spec/features/merge_requests/target_branch_spec.rb b/spec/features/merge_requests/target_branch_spec.rb
index 4328d66c748..9bbf2610bcb 100644
--- a/spec/features/merge_requests/target_branch_spec.rb
+++ b/spec/features/merge_requests/target_branch_spec.rb
@@ -1,19 +1,16 @@
require 'spec_helper'
-describe 'Target branch', feature: true, js: true do
+describe 'Target branch', js: true do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
def path_to_merge_request
- namespace_project_merge_request_path(
- project.namespace,
- project, merge_request
- )
+ project_merge_request_path(project, merge_request)
end
before do
- gitlab_sign_in user
+ sign_in user
project.team << [user, :master]
end
diff --git a/spec/features/merge_requests/toggle_whitespace_changes_spec.rb b/spec/features/merge_requests/toggle_whitespace_changes_spec.rb
index cba9a2cda99..dd989fd49b2 100644
--- a/spec/features/merge_requests/toggle_whitespace_changes_spec.rb
+++ b/spec/features/merge_requests/toggle_whitespace_changes_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Toggle Whitespace Changes', js: true, feature: true do
+feature 'Toggle Whitespace Changes', js: true do
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
merge_request = create(:merge_request)
project = merge_request.source_project
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit diffs_project_merge_request_path(project, merge_request)
end
it 'has a button to toggle whitespace changes' do
diff --git a/spec/features/merge_requests/toggler_behavior_spec.rb b/spec/features/merge_requests/toggler_behavior_spec.rb
index c4c06e9a7a0..4e5ec9fbd2d 100644
--- a/spec/features/merge_requests/toggler_behavior_spec.rb
+++ b/spec/features/merge_requests/toggler_behavior_spec.rb
@@ -1,17 +1,17 @@
require 'spec_helper'
-feature 'toggler_behavior', js: true, feature: true do
+feature 'toggler_behavior', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project, author: user) }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:fragment_id) { "#note_#{note.id}" }
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
project = merge_request.source_project
page.current_window.resize_to(1000, 300)
- visit "#{namespace_project_merge_request_path(project.namespace, project, merge_request)}#{fragment_id}"
+ visit "#{project_merge_request_path(project, merge_request)}#{fragment_id}"
end
describe 'scroll position' do
diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb
index d0418c74699..cf30a687df8 100644
--- a/spec/features/merge_requests/update_merge_requests_spec.rb
+++ b/spec/features/merge_requests/update_merge_requests_spec.rb
@@ -1,19 +1,19 @@
require 'rails_helper'
-feature 'Multiple merge requests updating from merge_requests#index', feature: true do
+feature 'Multiple merge requests updating from merge_requests#index' do
let!(:user) { create(:user)}
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'status', js: true do
describe 'close merge request' do
before do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it 'closes merge request' do
@@ -26,7 +26,7 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t
describe 'reopen merge request' do
before do
merge_request.close
- visit namespace_project_merge_requests_path(project.namespace, project, state: 'closed')
+ visit project_merge_requests_path(project, state: 'closed')
end
it 'reopens merge request' do
@@ -40,7 +40,7 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t
context 'assignee', js: true do
describe 'set assignee' do
before do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it "updates merge request with assignee" do
@@ -56,7 +56,7 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t
before do
merge_request.assignee = user
merge_request.save
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it "removes assignee from the merge request" do
@@ -72,7 +72,7 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t
describe 'set milestone' do
before do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it "updates merge request with milestone" do
@@ -86,7 +86,7 @@ feature 'Multiple merge requests updating from merge_requests#index', feature: t
before do
merge_request.milestone = milestone
merge_request.save
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it "removes milestone from the merge request" do
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index cabb8e455f9..d62b035b40b 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe 'Projects > Merge requests > User lists merge requests', feature: true do
+describe 'Projects > Merge requests > User lists merge requests' do
include MergeRequestHelpers
include SortingHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
before do
@@ -37,7 +37,7 @@ describe 'Projects > Merge requests > User lists merge requests', feature: true
it 'filters on no assignee' do
visit_merge_requests(project, assignee_id: IssuableFinder::NONE)
- expect(current_path).to eq(namespace_project_merge_requests_path(project.namespace, project))
+ expect(current_path).to eq(project_merge_requests_path(project))
expect(page).to have_content 'merge_lfs'
expect(page).not_to have_content 'fix'
expect(page).not_to have_content 'markdown'
@@ -136,7 +136,7 @@ describe 'Projects > Merge requests > User lists merge requests', feature: true
end
it 'sorts by recently due milestone' do
- visit namespace_project_merge_requests_path(project.namespace, project,
+ visit project_merge_requests_path(project,
label_name: [label.name, label2.name],
assignee_id: user.id,
sort: sort_value_milestone_soon)
diff --git a/spec/features/merge_requests/user_posts_diff_notes_spec.rb b/spec/features/merge_requests/user_posts_diff_notes_spec.rb
index 2574e1bb1d5..24372244bd7 100644
--- a/spec/features/merge_requests/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_requests/user_posts_diff_notes_spec.rb
@@ -7,7 +7,7 @@ feature 'Merge requests > User posts diff notes', :js do
before do
project.add_developer(user)
- gitlab_sign_in(user)
+ sign_in(user)
end
let(:comment_button_class) { '.add-diff-note' }
@@ -17,7 +17,7 @@ feature 'Merge requests > User posts diff notes', :js do
context 'when hovering over a parallel view diff file' do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: 'parallel')
+ visit diffs_project_merge_request_path(project, merge_request, view: 'parallel')
end
context 'with an old line on the left and no line on the right' do
@@ -92,7 +92,7 @@ feature 'Merge requests > User posts diff notes', :js do
context 'when hovering over an inline view diff file' do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: 'inline')
+ visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
end
context 'with a new line' do
@@ -136,9 +136,9 @@ feature 'Merge requests > User posts diff notes', :js do
context 'when hovering over a diff discussion' do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: 'inline')
+ visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not allow commenting' do
@@ -149,7 +149,7 @@ feature 'Merge requests > User posts diff notes', :js do
context 'when cancelling the comment addition' do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: 'inline')
+ visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
end
context 'with a new line' do
@@ -161,7 +161,7 @@ feature 'Merge requests > User posts diff notes', :js do
describe 'with muliple note forms' do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: 'inline')
+ visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
click_diff_line(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
click_diff_line(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
end
@@ -181,7 +181,7 @@ feature 'Merge requests > User posts diff notes', :js do
context 'when the MR only supports legacy diff notes' do
before do
merge_request.merge_request_diff.update_attributes(start_commit_sha: nil)
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, view: 'inline')
+ visit diffs_project_merge_request_path(project, merge_request, view: 'inline')
end
context 'with a new line' do
diff --git a/spec/features/merge_requests/user_posts_notes_spec.rb b/spec/features/merge_requests/user_posts_notes_spec.rb
index 12f987e12ea..74d21822a59 100644
--- a/spec/features/merge_requests/user_posts_notes_spec.rb
+++ b/spec/features/merge_requests/user_posts_notes_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'Merge requests > User posts notes', :js do
include NoteInteractionHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:merge_request) do
create(:merge_request, source_project: project, target_project: project)
end
@@ -13,8 +13,8 @@ describe 'Merge requests > User posts notes', :js do
end
before do
- gitlab_sign_in :admin
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(create(:admin))
+ visit project_merge_request_path(project, merge_request)
end
subject { page }
diff --git a/spec/features/merge_requests/user_sees_system_notes_spec.rb b/spec/features/merge_requests/user_sees_system_notes_spec.rb
index 0d88a8172b0..03dc61c2efa 100644
--- a/spec/features/merge_requests/user_sees_system_notes_spec.rb
+++ b/spec/features/merge_requests/user_sees_system_notes_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
feature 'Merge requests > User sees system notes' do
- let(:public_project) { create(:project, :public) }
- let(:private_project) { create(:project, :private) }
+ let(:public_project) { create(:project, :public, :repository) }
+ let(:private_project) { create(:project, :private, :repository) }
let(:issue) { create(:issue, project: private_project) }
let(:merge_request) { create(:merge_request, source_project: public_project, source_branch: 'markdown') }
let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: public_project, note: "mentioned in #{issue.to_reference(public_project)}") }
@@ -11,11 +11,11 @@ feature 'Merge requests > User sees system notes' do
before do
user = create(:user)
private_project.add_developer(user)
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'shows the system note' do
- visit namespace_project_merge_request_path(public_project.namespace, public_project, merge_request)
+ visit project_merge_request_path(public_project, merge_request)
expect(page).to have_css('.system-note')
end
@@ -23,7 +23,7 @@ feature 'Merge requests > User sees system notes' do
context 'when not logged-in' do
it 'hides the system note' do
- visit namespace_project_merge_request_path(public_project.namespace, public_project, merge_request)
+ visit project_merge_request_path(public_project, merge_request)
expect(page).not_to have_css('.system-note')
end
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 71aa71e380e..43cab65d287 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-feature 'Merge Requests > User uses quick actions', feature: true, js: true do
+feature 'Merge Requests > User uses quick actions', js: true do
include QuickActionsHelpers
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
@@ -16,14 +16,22 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
describe 'merge-request-only commands' do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
end
after do
wait_for_requests
end
+ describe 'time tracking' do
+ before do
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it_behaves_like 'issuable time tracker'
+ end
+
describe 'toggling the WIP prefix in the title from note' do
context 'when the current user can toggle the WIP prefix' do
it 'adds the WIP: prefix to the title' do
@@ -51,9 +59,9 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
- gitlab_sign_out
- gitlab_sign_in(guest)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_out(:user)
+ sign_in(guest)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not change the WIP prefix' do
@@ -97,9 +105,9 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
- gitlab_sign_out
- gitlab_sign_in(guest)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_out(:user)
+ sign_in(guest)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not merge the MR' do
@@ -121,17 +129,17 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
end
describe '/target_branch command in merge request' do
- let(:another_project) { create(:project, :public) }
+ let(:another_project) { create(:project, :public, :repository) }
let(:new_url_opts) { { merge_request: { source_branch: 'feature' } } }
before do
- gitlab_sign_out
+ sign_out(:user)
another_project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'changes target_branch in new merge_request' do
- visit new_namespace_project_merge_request_path(another_project.namespace, another_project, new_url_opts)
+ visit project_new_merge_request_path(another_project, new_url_opts)
fill_in "merge_request_title", with: 'My brand new feature'
fill_in "merge_request_description", with: "le feature \n/target_branch fix\nFeature description:"
@@ -145,7 +153,7 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
it 'does not change target branch when merge request is edited' do
new_merge_request = create(:merge_request, source_project: another_project)
- visit edit_namespace_project_merge_request_path(another_project.namespace, another_project, new_merge_request)
+ visit edit_project_merge_request_path(another_project, new_merge_request)
fill_in "merge_request_description", with: "Want to update target branch\n/target_branch fix\n"
click_button "Save changes"
@@ -181,9 +189,9 @@ feature 'Merge Requests > User uses quick actions', feature: true, js: true do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
- gitlab_sign_out
- gitlab_sign_in(guest)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_out(:user)
+ sign_in(guest)
+ visit project_merge_request_path(project, merge_request)
end
it 'does not change target branch' do
diff --git a/spec/features/merge_requests/versions_spec.rb b/spec/features/merge_requests/versions_spec.rb
index 8ee45fb81ee..6669522dd7a 100644
--- a/spec/features/merge_requests/versions_spec.rb
+++ b/spec/features/merge_requests/versions_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Merge Request versions', js: true, feature: true do
+feature 'Merge Request versions', js: true do
let(:merge_request) { create(:merge_request, importing: true) }
let(:project) { merge_request.source_project }
let!(:merge_request_diff1) { merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
@@ -8,8 +8,8 @@ feature 'Merge Request versions', js: true, feature: true do
let!(:merge_request_diff3) { merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
before do
- gitlab_sign_in :admin
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ sign_in(create(:admin))
+ visit diffs_project_merge_request_path(project, merge_request)
end
it 'show the latest version of the diff' do
@@ -96,8 +96,7 @@ feature 'Merge Request versions', js: true, feature: true do
end
it 'has a path with comparison context' do
- expect(page).to have_current_path diffs_namespace_project_merge_request_path(
- project.namespace,
+ expect(page).to have_current_path diffs_project_merge_request_path(
project,
merge_request.iid,
diff_id: merge_request_diff3.id,
diff --git a/spec/features/merge_requests/widget_deployments_spec.rb b/spec/features/merge_requests/widget_deployments_spec.rb
index e82e69c5f4a..c0221525c9f 100644
--- a/spec/features/merge_requests/widget_deployments_spec.rb
+++ b/spec/features/merge_requests/widget_deployments_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Widget Deployments Header', feature: true, js: true do
+feature 'Widget Deployments Header', js: true do
describe 'when deployed to an environment' do
given(:user) { create(:user) }
given(:project) { merge_request.target_project }
@@ -12,9 +12,9 @@ feature 'Widget Deployments Header', feature: true, js: true do
given!(:manual) { }
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
scenario 'displays that the environment is deployed' do
diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb
index 3ac1f603de6..69e31c7481f 100644
--- a/spec/features/merge_requests/widget_spec.rb
+++ b/spec/features/merge_requests/widget_spec.rb
@@ -1,27 +1,25 @@
require 'rails_helper'
-describe 'Merge request', :feature, :js do
+describe 'Merge request', :js do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'new merge request' do
before do
- visit new_namespace_project_merge_request_path(
- project.namespace,
+ visit project_new_merge_request_path(
project,
merge_request: {
source_project_id: project.id,
target_project_id: project.id,
source_branch: 'feature',
target_branch: 'master'
- }
- )
+ })
end
it 'shows widget status after creating new merge request' do
@@ -44,7 +42,7 @@ describe 'Merge request', :feature, :js do
end
before do
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'shows environments link' do
@@ -71,7 +69,7 @@ describe 'Merge request', :feature, :js do
type: 'CiService',
category: 'ci')
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'has danger button while waiting for external CI status' do
@@ -92,7 +90,7 @@ describe 'Merge request', :feature, :js do
head_pipeline_of: merge_request)
create(:ci_build, :pending, pipeline: pipeline)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'has danger button when not succeeded' do
@@ -112,9 +110,7 @@ describe 'Merge request', :feature, :js do
status: :manual,
head_pipeline_of: merge_request)
- visit namespace_project_merge_request_path(project.namespace,
- project,
- merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'shows information about blocked pipeline' do
@@ -136,7 +132,7 @@ describe 'Merge request', :feature, :js do
head_pipeline_of: merge_request)
create(:ci_build, :pending, pipeline: pipeline)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'has info button when MWBS button' do
@@ -154,7 +150,7 @@ describe 'Merge request', :feature, :js do
merge_error: 'Something went wrong'
)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'shows information about the merge error' do
@@ -175,7 +171,7 @@ describe 'Merge request', :feature, :js do
merge_error: 'Something went wrong'
)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'shows information about the merge error' do
@@ -191,7 +187,7 @@ describe 'Merge request', :feature, :js do
context 'merge error' do
before do
allow_any_instance_of(Repository).to receive(:merge).and_return(false)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'updates the MR widget' do
@@ -204,15 +200,15 @@ describe 'Merge request', :feature, :js do
end
context 'user can merge into source project but cannot push to fork', js: true do
- let(:fork_project) { create(:project, :public) }
+ let(:fork_project) { create(:project, :public, :repository) }
let(:user2) { create(:user) }
before do
project.team << [user2, :master]
- gitlab_sign_out
- gitlab_sign_in user2
+ sign_out(:user)
+ sign_in(user2)
merge_request.update(target_project: fork_project)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
it 'user can merge into the source project' do
diff --git a/spec/features/merge_requests/wip_message_spec.rb b/spec/features/merge_requests/wip_message_spec.rb
index 72d001bf408..b422c76249d 100644
--- a/spec/features/merge_requests/wip_message_spec.rb
+++ b/spec/features/merge_requests/wip_message_spec.rb
@@ -1,26 +1,24 @@
require 'spec_helper'
-feature 'Work In Progress help message', feature: true do
- let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+feature 'Work In Progress help message' do
+ let!(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'with WIP commits' do
it 'shows a specific WIP hint' do
- visit new_namespace_project_merge_request_path(
- project.namespace,
+ visit project_new_merge_request_path(
project,
merge_request: {
source_project_id: project.id,
target_project_id: project.id,
source_branch: 'wip',
target_branch: 'master'
- }
- )
+ })
within_wip_explanation do
expect(page).to have_text(
@@ -32,16 +30,14 @@ feature 'Work In Progress help message', feature: true do
context 'without WIP commits' do
it 'shows the regular WIP message' do
- visit new_namespace_project_merge_request_path(
- project.namespace,
+ visit project_new_merge_request_path(
project,
merge_request: {
source_project_id: project.id,
target_project_id: project.id,
source_branch: 'fix',
target_branch: 'master'
- }
- )
+ })
within_wip_explanation do
expect(page).not_to have_text(
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index 58989581ffe..1d05184d6fc 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -1,17 +1,19 @@
require 'rails_helper'
-feature 'Milestone', feature: true do
- let(:project) { create(:empty_project, :public) }
+feature 'Milestone' do
+ let(:group) { create(:group, :public) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
let(:user) { create(:user) }
before do
+ create(:group_member, group: group, user: user)
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
feature 'Create a milestone' do
scenario 'shows an informative message for a new milestone' do
- visit new_namespace_project_milestone_path(project.namespace, project)
+ visit new_project_milestone_path(project)
page.within '.milestone-form' do
fill_in "milestone_title", with: '8.7'
@@ -31,23 +33,36 @@ feature 'Milestone', feature: true do
milestone = create(:milestone, project: project, title: 8.7)
create(:issue, title: "Bugfix1", project: project, milestone: milestone, state: "closed")
- visit namespace_project_milestone_path(project.namespace, project, milestone)
+ visit project_milestone_path(project, milestone)
expect(find('.alert-success')).to have_content('All issues for this milestone are closed. You may close this milestone now.')
end
end
- feature 'Open a milestone with an existing title' do
- scenario 'displays validation message' do
+ feature 'Open a project milestone with an existing title' do
+ scenario 'displays validation message when there is a project milestone with same title' do
milestone = create(:milestone, project: project, title: 8.7)
- visit new_namespace_project_milestone_path(project.namespace, project)
+ visit new_project_milestone_path(project)
page.within '.milestone-form' do
fill_in "milestone_title", with: milestone.title
end
find('input[name="commit"]').click
- expect(find('.alert-danger')).to have_content('Title has already been taken')
+ expect(find('.alert-danger')).to have_content('already being used for another group or project milestone.')
+ end
+
+ scenario 'displays validation message when there is a group milestone with same title' do
+ milestone = create(:milestone, project_id: nil, group: project.group, title: 8.7)
+
+ visit new_group_milestone_path(project.group)
+
+ page.within '.milestone-form' do
+ fill_in "milestone_title", with: milestone.title
+ end
+ find('input[name="commit"]').click
+
+ expect(find('.alert-danger')).to have_content('already being used for another group or project milestone.')
end
end
end
diff --git a/spec/features/milestones/show_spec.rb b/spec/features/milestones/show_spec.rb
index cdf6cfba402..199a5ba83b3 100644
--- a/spec/features/milestones/show_spec.rb
+++ b/spec/features/milestones/show_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Milestone show', feature: true do
+describe 'Milestone show' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:milestone) { create(:milestone, project: project) }
@@ -9,11 +9,11 @@ describe 'Milestone show', feature: true do
before do
project.add_user(user, :developer)
- gitlab_sign_in(user)
+ sign_in(user)
end
def visit_milestone
- visit namespace_project_milestone_path(project.namespace, project, milestone)
+ visit project_milestone_path(project, milestone)
end
it 'avoids N+1 database queries' do
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
new file mode 100644
index 00000000000..49d8e52f861
--- /dev/null
+++ b/spec/features/oauth_login_spec.rb
@@ -0,0 +1,114 @@
+require 'spec_helper'
+
+feature 'OAuth Login', :js, :allow_forgery_protection do
+ include DeviseHelpers
+
+ def enter_code(code)
+ fill_in 'user_otp_attempt', with: code
+ click_button 'Verify code'
+ end
+
+ def stub_omniauth_config(provider)
+ OmniAuth.config.add_mock(provider, OmniAuth::AuthHash.new(provider: provider.to_s, uid: "12345"))
+ set_devise_mapping(context: Rails.application)
+ Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider]
+ end
+
+ providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2,
+ :facebook, :cas3, :auth0, :authentiq]
+
+ before(:all) do
+ # The OmniAuth `full_host` parameter doesn't get set correctly (it gets set to something like `http://localhost`
+ # here), and causes integration tests to fail with 404s. We set the `full_host` by removing the request path (and
+ # anything after it) from the request URI.
+ @omniauth_config_full_host = OmniAuth.config.full_host
+ OmniAuth.config.full_host = ->(request) { request['REQUEST_URI'].sub(/#{request['REQUEST_PATH']}.*/, '') }
+ end
+
+ after(:all) do
+ OmniAuth.config.full_host = @omniauth_config_full_host
+ end
+
+ providers.each do |provider|
+ context "when the user logs in using the #{provider} provider" do
+ context 'when two-factor authentication is disabled' do
+ it 'logs the user in' do
+ stub_omniauth_config(provider)
+ user = create(:omniauth_user, extern_uid: 'my-uid', provider: provider.to_s)
+ login_via(provider.to_s, user, 'my-uid')
+
+ expect(current_path).to eq root_path
+ end
+ end
+
+ context 'when two-factor authentication is enabled' do
+ it 'logs the user in' do
+ stub_omniauth_config(provider)
+ user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider.to_s)
+ login_via(provider.to_s, user, 'my-uid')
+
+ enter_code(user.current_otp)
+ expect(current_path).to eq root_path
+ end
+ end
+
+ context 'when "remember me" is checked' do
+ context 'when two-factor authentication is disabled' do
+ it 'remembers the user after a browser restart' do
+ stub_omniauth_config(provider)
+ user = create(:omniauth_user, extern_uid: 'my-uid', provider: provider.to_s)
+ login_via(provider.to_s, user, 'my-uid', remember_me: true)
+
+ clear_browser_session
+
+ visit(root_path)
+ expect(current_path).to eq root_path
+ end
+ end
+
+ context 'when two-factor authentication is enabled' do
+ it 'remembers the user after a browser restart' do
+ stub_omniauth_config(provider)
+ user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider.to_s)
+ login_via(provider.to_s, user, 'my-uid', remember_me: true)
+ enter_code(user.current_otp)
+
+ clear_browser_session
+
+ visit(root_path)
+ expect(current_path).to eq root_path
+ end
+ end
+ end
+
+ context 'when "remember me" is not checked' do
+ context 'when two-factor authentication is disabled' do
+ it 'does not remember the user after a browser restart' do
+ stub_omniauth_config(provider)
+ user = create(:omniauth_user, extern_uid: 'my-uid', provider: provider.to_s)
+ login_via(provider.to_s, user, 'my-uid', remember_me: false)
+
+ clear_browser_session
+
+ visit(root_path)
+ expect(current_path).to eq new_user_session_path
+ end
+ end
+
+ context 'when two-factor authentication is enabled' do
+ it 'does not remember the user after a browser restart' do
+ stub_omniauth_config(provider)
+ user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider.to_s)
+ login_via(provider.to_s, user, 'my-uid', remember_me: false)
+ enter_code(user.current_otp)
+
+ clear_browser_session
+
+ visit(root_path)
+ expect(current_path).to eq new_user_session_path
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
index b8966cf621c..81b0a2f541b 100644
--- a/spec/features/participants_autocomplete_spec.rb
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -8,7 +8,7 @@ feature 'Member autocomplete', :js do
before do
note # actually create the note
- gitlab_sign_in(user)
+ sign_in(user)
end
shared_examples "open suggestions when typing @" do
@@ -29,7 +29,7 @@ feature 'Member autocomplete', :js do
context 'adding a new note on a Issue' do
let(:noteable) { create(:issue, author: author, project: project) }
before do
- visit namespace_project_issue_path(project.namespace, project, noteable)
+ visit project_issue_path(project, noteable)
end
include_examples "open suggestions when typing @"
@@ -42,7 +42,7 @@ feature 'Member autocomplete', :js do
target_project: project, author: author)
end
before do
- visit namespace_project_merge_request_path(project.namespace, project, noteable)
+ visit project_merge_request_path(project, noteable)
end
include_examples "open suggestions when typing @"
@@ -54,9 +54,10 @@ feature 'Member autocomplete', :js do
let(:note) { create(:note_on_commit, project: project, commit_id: project.commit.id) }
before do
- allow_any_instance_of(Commit).to receive(:author).and_return(author)
+ allow(User).to receive(:find_by_any_email)
+ .with(noteable.author_email.downcase).and_return(author)
- visit namespace_project_commit_path(project.namespace, project, noteable)
+ visit project_commit_path(project, noteable)
end
include_examples "open suggestions when typing @"
diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb
index 257d363438c..5e1e7dc078f 100644
--- a/spec/features/password_reset_spec.rb
+++ b/spec/features/password_reset_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Password reset', feature: true do
+feature 'Password reset' do
describe 'throttling' do
it 'sends reset instructions when not previously sent' do
user = create(:user)
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index bb4263d83f3..672022304da 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe 'Profile account page', feature: true do
+describe 'Profile account page' do
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'when signup is enabled' do
diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb
index 33fd29b429b..56c1f7ae9c7 100644
--- a/spec/features/profiles/account_spec.rb
+++ b/spec/features/profiles/account_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-feature 'Profile > Account', feature: true do
+feature 'Profile > Account' do
given(:user) { create(:user, username: 'foo') }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'Change username' do
@@ -27,7 +27,7 @@ feature 'Profile > Account', feature: true do
end
context 'with a project' do
- given!(:project) { create(:project, namespace: user.namespace, path: 'project') }
+ given!(:project) { create(:empty_project, namespace: user.namespace) }
given(:new_project_path) { "/#{new_username}/#{project.path}" }
given(:old_project_path) { "/#{user.username}/#{project.path}" }
@@ -43,14 +43,14 @@ feature 'Profile > Account', feature: true do
update_username(new_username)
visit new_project_path
expect(current_path).to eq(new_project_path)
- expect(find('h1.project-title')).to have_content(project.name)
+ expect(find('h1.title')).to have_content(project.path)
end
scenario 'the old project path redirects to the new path' do
update_username(new_username)
visit old_project_path
expect(current_path).to eq(new_project_path)
- expect(find('h1.project-title')).to have_content(project.name)
+ expect(find('h1.title')).to have_content(project.path)
end
end
end
diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb
index 1a162d6be0e..35793539e0e 100644
--- a/spec/features/profiles/chat_names_spec.rb
+++ b/spec/features/profiles/chat_names_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'Profile > Chat', feature: true do
+feature 'Profile > Chat' do
given(:user) { create(:user) }
given(:service) { create(:service) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'uses authorization link' do
diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb
new file mode 100644
index 00000000000..6edc482b47e
--- /dev/null
+++ b/spec/features/profiles/gpg_keys_spec.rb
@@ -0,0 +1,58 @@
+require 'rails_helper'
+
+feature 'Profile > GPG Keys' do
+ let(:user) { create(:user, email: GpgHelpers::User2.emails.first) }
+
+ before do
+ login_as(user)
+ end
+
+ describe 'User adds a key' do
+ before do
+ visit profile_gpg_keys_path
+ end
+
+ scenario 'saves the new key' do
+ fill_in('Key', with: GpgHelpers::User2.public_key)
+ click_button('Add key')
+
+ expect(page).to have_content('bette.cartwright@example.com Verified')
+ expect(page).to have_content('bette.cartwright@example.net Unverified')
+ expect(page).to have_content(GpgHelpers::User2.fingerprint)
+ end
+ end
+
+ scenario 'User sees their key' do
+ create(:gpg_key, user: user, key: GpgHelpers::User2.public_key)
+ visit profile_gpg_keys_path
+
+ expect(page).to have_content('bette.cartwright@example.com Verified')
+ expect(page).to have_content('bette.cartwright@example.net Unverified')
+ expect(page).to have_content(GpgHelpers::User2.fingerprint)
+ end
+
+ scenario 'User removes a key via the key index' do
+ create(:gpg_key, user: user, key: GpgHelpers::User2.public_key)
+ visit profile_gpg_keys_path
+
+ click_link('Remove')
+
+ expect(page).to have_content('Your GPG keys (0)')
+ end
+
+ scenario 'User revokes a key via the key index' do
+ gpg_key = create :gpg_key, user: user, key: GpgHelpers::User2.public_key
+ gpg_signature = create :gpg_signature, gpg_key: gpg_key, valid_signature: true
+
+ visit profile_gpg_keys_path
+
+ click_link('Revoke')
+
+ expect(page).to have_content('Your GPG keys (0)')
+
+ expect(gpg_signature.reload).to have_attributes(
+ valid_signature: false,
+ gpg_key: nil
+ )
+ end
+end
diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb
index 13f9afd4ce0..6541ea6bf57 100644
--- a/spec/features/profiles/keys_spec.rb
+++ b/spec/features/profiles/keys_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-feature 'Profile > SSH Keys', feature: true do
+feature 'Profile > SSH Keys' do
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'User adds a key' do
diff --git a/spec/features/profiles/oauth_applications_spec.rb b/spec/features/profiles/oauth_applications_spec.rb
index a6f9beafe17..45f78444362 100644
--- a/spec/features/profiles/oauth_applications_spec.rb
+++ b/spec/features/profiles/oauth_applications_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe 'Profile > Applications', feature: true do
+describe 'Profile > Applications' do
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'User manages applications', js: true do
diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb
index 2d36f3d020f..2c757f99a27 100644
--- a/spec/features/profiles/password_spec.rb
+++ b/spec/features/profiles/password_spec.rb
@@ -1,44 +1,74 @@
require 'spec_helper'
-describe 'Profile > Password', feature: true do
- let(:user) { create(:user, password_automatically_set: true) }
+describe 'Profile > Password' do
+ context 'Password authentication enabled' do
+ let(:user) { create(:user, password_automatically_set: true) }
- before do
- gitlab_sign_in(user)
- visit edit_profile_password_path
- end
+ before do
+ sign_in(user)
+ visit edit_profile_password_path
+ end
- def fill_passwords(password, confirmation)
- fill_in 'New password', with: password
- fill_in 'Password confirmation', with: confirmation
+ def fill_passwords(password, confirmation)
+ fill_in 'New password', with: password
+ fill_in 'Password confirmation', with: confirmation
- click_button 'Save password'
- end
+ click_button 'Save password'
+ end
+
+ context 'User with password automatically set' do
+ describe 'User puts different passwords in the field and in the confirmation' do
+ it 'shows an error message' do
+ fill_passwords('mypassword', 'mypassword2')
- context 'User with password automatically set' do
- describe 'User puts different passwords in the field and in the confirmation' do
- it 'shows an error message' do
- fill_passwords('mypassword', 'mypassword2')
+ page.within('.alert-danger') do
+ expect(page).to have_content("Password confirmation doesn't match Password")
+ end
+ end
+
+ it 'does not contain the current password field after an error' do
+ fill_passwords('mypassword', 'mypassword2')
- page.within('.alert-danger') do
- expect(page).to have_content("Password confirmation doesn't match Password")
+ expect(page).to have_no_field('user[current_password]')
end
end
- it 'does not contains the current password field after an error' do
- fill_passwords('mypassword', 'mypassword2')
+ describe 'User puts the same passwords in the field and in the confirmation' do
+ it 'shows a success message' do
+ fill_passwords('mypassword', 'mypassword')
- expect(page).to have_no_field('user[current_password]')
+ page.within('.flash-notice') do
+ expect(page).to have_content('Password was successfully updated. Please login with it')
+ end
+ end
end
end
+ end
- describe 'User puts the same passwords in the field and in the confirmation' do
- it 'shows a success message' do
- fill_passwords('mypassword', 'mypassword')
+ context 'Password authentication unavailable' do
+ before do
+ gitlab_sign_in(user)
+ end
- page.within('.flash-notice') do
- expect(page).to have_content('Password was successfully updated. Please login with it')
- end
+ context 'Regular user' do
+ let(:user) { create(:user) }
+
+ it 'renders 404 when sign-in is disabled' do
+ stub_application_setting(password_authentication_enabled: false)
+
+ visit edit_profile_password_path
+
+ expect(page).to have_http_status(404)
+ end
+ end
+
+ context 'LDAP user' do
+ let(:user) { create(:omniauth_user, provider: 'ldapmain') }
+
+ it 'renders 404' do
+ visit edit_profile_password_path
+
+ expect(page).to have_http_status(404)
end
end
end
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index d7acaaf1eb8..f3124bbf29e 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-describe 'Profile > Personal Access Tokens', feature: true, js: true do
+describe 'Profile > Personal Access Tokens', js: true do
let(:user) { create(:user) }
def active_personal_access_tokens
find(".table.active-tokens")
end
- def inactive_personal_access_tokens
- find(".table.inactive-tokens")
+ def no_personal_access_tokens_message
+ find(".settings-message")
end
def created_personal_access_token
@@ -23,7 +23,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
end
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe "token creation" do
@@ -80,14 +80,16 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
visit profile_personal_access_tokens_path
click_on "Revoke"
- expect(inactive_personal_access_tokens).to have_text(personal_access_token.name)
+ expect(page).to have_selector(".settings-message")
+ expect(no_personal_access_tokens_message).to have_text("This user has no active Personal Access Tokens.")
end
- it "moves expired tokens to the 'inactive' section" do
+ it "removes expired tokens from 'active' section" do
personal_access_token.update(expires_at: 5.days.ago)
visit profile_personal_access_tokens_path
- expect(inactive_personal_access_tokens).to have_text(personal_access_token.name)
+ expect(page).to have_selector(".settings-message")
+ expect(no_personal_access_tokens_message).to have_text("This user has no active Personal Access Tokens.")
end
context "when revocation fails" do
diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb
index efbae703943..3b57ff47d33 100644
--- a/spec/features/profiles/preferences_spec.rb
+++ b/spec/features/profiles/preferences_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe 'Profile > Preferences', feature: true do
+describe 'Profile > Preferences' do
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
visit profile_preferences_path
end
diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb
index c0092836e3b..6a4173d43e1 100644
--- a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb
+++ b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Profile > Notifications > User changes notified_of_own_activity setting', feature: true, js: true do
+feature 'Profile > Notifications > User changes notified_of_own_activity setting', js: true do
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'User opts into receiving notifications about their own activity' do
diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb
new file mode 100644
index 00000000000..e98cec79d87
--- /dev/null
+++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+feature 'User visits the notifications tab', js: true do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ visit(profile_notifications_path)
+ end
+
+ it 'changes the project notifications setting' do
+ expect(page).to have_content('Notifications')
+
+ first('#notifications-button').trigger('click')
+ click_link('On mention')
+
+ expect(page).to have_content('On mention')
+ end
+end
diff --git a/spec/features/projects/activity/rss_spec.rb b/spec/features/projects/activity/rss_spec.rb
index 84c81d43448..b054f543dc6 100644
--- a/spec/features/projects/activity/rss_spec.rb
+++ b/spec/features/projects/activity/rss_spec.rb
@@ -1,8 +1,9 @@
require 'spec_helper'
feature 'Project Activity RSS' do
+ let(:user) { create(:user) }
let(:project) { create(:empty_project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:path) { activity_namespace_project_path(project.namespace, project) }
+ let(:path) { activity_project_path(project) }
before do
create(:issue, project: project)
@@ -10,9 +11,8 @@ feature 'Project Activity RSS' do
context 'when signed in' do
before do
- user = create(:user)
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/projects/artifacts/browse_spec.rb b/spec/features/projects/artifacts/browse_spec.rb
index 68375956273..f5f7eba8e40 100644
--- a/spec/features/projects/artifacts/browse_spec.rb
+++ b/spec/features/projects/artifacts/browse_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Browse artifact', :js, feature: true do
- let(:project) { create(:project, :public) }
- let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
+feature 'Browse artifact', :js do
+ let(:project) { create(:empty_project, :public) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
def browse_path(path)
- browse_namespace_project_job_artifacts_path(project.namespace, project, job, path)
+ browse_project_job_artifacts_path(project, job, path)
end
context 'when visiting old URL' do
diff --git a/spec/features/projects/artifacts/download_spec.rb b/spec/features/projects/artifacts/download_spec.rb
index dd9454840ee..c1bba8c15c4 100644
--- a/spec/features/projects/artifacts/download_spec.rb
+++ b/spec/features/projects/artifacts/download_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Download artifact', :js, feature: true do
- let(:project) { create(:project, :public) }
- let(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project, sha: project.commit.sha, ref: 'master') }
+feature 'Download artifact', :js do
+ let(:project) { create(:empty_project, :public) }
+ let(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project) }
let(:job) { create(:ci_build, :artifacts, :success, pipeline: pipeline) }
shared_examples 'downloading' do
@@ -22,7 +22,7 @@ feature 'Download artifact', :js, feature: true do
context 'via job id' do
let(:download_url) do
- download_namespace_project_job_artifacts_path(project.namespace, project, job)
+ download_project_job_artifacts_path(project, job)
end
it_behaves_like 'downloading'
@@ -30,7 +30,7 @@ feature 'Download artifact', :js, feature: true do
context 'via branch name and job name' do
let(:download_url) do
- latest_succeeded_namespace_project_artifacts_path(project.namespace, project, "#{pipeline.ref}/download", job: job.name)
+ latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name)
end
it_behaves_like 'downloading'
@@ -44,7 +44,7 @@ feature 'Download artifact', :js, feature: true do
context 'via job id' do
let(:download_url) do
- download_namespace_project_job_artifacts_path(project.namespace, project, job)
+ download_project_job_artifacts_path(project, job)
end
it_behaves_like 'downloading'
@@ -52,7 +52,7 @@ feature 'Download artifact', :js, feature: true do
context 'via branch name and job name' do
let(:download_url) do
- latest_succeeded_namespace_project_artifacts_path(project.namespace, project, "#{pipeline.ref}/download", job: job.name)
+ latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name)
end
it_behaves_like 'downloading'
diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb
index 860373e531b..4c268b876ea 100644
--- a/spec/features/projects/artifacts/file_spec.rb
+++ b/spec/features/projects/artifacts/file_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Artifact file', :js, feature: true do
- let(:project) { create(:project, :public) }
- let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
+feature 'Artifact file', :js do
+ let(:project) { create(:empty_project, :public) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
def visit_file(path)
@@ -10,7 +10,7 @@ feature 'Artifact file', :js, feature: true do
end
def file_path(path)
- file_namespace_project_job_artifacts_path(project.namespace, project, build, path)
+ file_project_job_artifacts_path(project, build, path)
end
context 'Text file' do
diff --git a/spec/features/projects/artifacts/raw_spec.rb b/spec/features/projects/artifacts/raw_spec.rb
index b589701729d..128e39e7803 100644
--- a/spec/features/projects/artifacts/raw_spec.rb
+++ b/spec/features/projects/artifacts/raw_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Raw artifact', :js, feature: true do
- let(:project) { create(:project, :public) }
- let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') }
+feature 'Raw artifact', :js do
+ let(:project) { create(:empty_project, :public) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
def raw_path(path)
- raw_namespace_project_job_artifacts_path(project.namespace, project, job, path)
+ raw_project_job_artifacts_path(project, job, path)
end
context 'when visiting old URL' do
diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb
index 9624e1a71b0..8cf4bfbf978 100644
--- a/spec/features/projects/badges/coverage_spec.rb
+++ b/spec/features/projects/badges/coverage_spec.rb
@@ -2,12 +2,12 @@ require 'spec_helper'
feature 'test coverage badge' do
given!(:user) { create(:user) }
- given!(:project) { create(:project, :private) }
+ given!(:project) { create(:empty_project, :private) }
context 'when user has access to view badge' do
background do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'user requests coverage badge image for pipeline' do
@@ -45,7 +45,7 @@ feature 'test coverage badge' do
end
context 'when user does not have access to view badge' do
- background { gitlab_sign_in(user) }
+ background { sign_in(user) }
scenario 'user requests test coverage badge image' do
show_test_coverage_badge
@@ -55,7 +55,7 @@ feature 'test coverage badge' do
end
def create_pipeline
- opts = { project: project, ref: 'master', sha: project.commit.id }
+ opts = { project: project }
create(:ci_pipeline, opts).tap do |pipeline|
yield pipeline
@@ -70,8 +70,7 @@ feature 'test coverage badge' do
end
def show_test_coverage_badge(job: nil)
- visit coverage_namespace_project_badges_path(
- project.namespace, project, ref: :master, job: job, format: :svg)
+ visit coverage_project_badges_path(project, ref: :master, job: job, format: :svg)
end
def expect_coverage_badge(coverage)
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index 348748152bb..89ae891037e 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -3,23 +3,23 @@ require 'spec_helper'
feature 'list of badges' do
background do
user = create(:user)
- project = create(:project)
+ project = create(:project, :repository)
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_pipelines_settings_path(project.namespace, project)
+ sign_in(user)
+ visit project_pipelines_settings_path(project)
end
scenario 'user wants to see build status badge' do
- page.within('.build-status') do
- expect(page).to have_content 'build status'
+ page.within('.pipeline-status') do
+ expect(page).to have_content 'pipeline status'
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
expect(page).to have_content 'AsciiDoc'
expect(page).to have_css('.highlight', count: 3)
- expect(page).to have_xpath("//img[@alt='build status']")
+ expect(page).to have_xpath("//img[@alt='pipeline status']")
page.within('.highlight', match: :first) do
- expect(page).to have_content 'badges/master/build.svg'
+ expect(page).to have_content 'badges/master/pipeline.svg'
end
end
end
@@ -40,14 +40,14 @@ feature 'list of badges' do
end
scenario 'user changes current ref of build status badge', js: true do
- page.within('.build-status') do
+ page.within('.pipeline-status') do
first('.js-project-refs-dropdown').click
page.within '.project-refs-form' do
click_link 'improve/awesome'
end
- expect(page).to have_content 'badges/improve/awesome/build.svg'
+ expect(page).to have_content 'badges/improve/awesome/pipeline.svg'
end
end
end
diff --git a/spec/features/projects/badges/pipeline_badge_spec.rb b/spec/features/projects/badges/pipeline_badge_spec.rb
new file mode 100644
index 00000000000..b83ea8f4eaa
--- /dev/null
+++ b/spec/features/projects/badges/pipeline_badge_spec.rb
@@ -0,0 +1,70 @@
+require 'spec_helper'
+
+feature 'Pipeline Badge' do
+ set(:project) { create(:project, :repository, :public) }
+ let(:ref) { project.default_branch }
+
+ # this can't be tested in the controller, as it bypasses the rails router
+ # and constructs a route based on the controller being tested
+ # Keep around until 10.0, see gitlab-org/gitlab-ce#35307
+ context 'when the deprecated badge is requested' do
+ it 'displays the badge' do
+ visit build_project_badges_path(project, ref: ref, format: :svg)
+
+ expect(page.status_code).to eq(200)
+ end
+ end
+
+ context 'when the project has a pipeline' do
+ let!(:pipeline) { create(:ci_empty_pipeline, project: project, ref: ref, sha: project.commit(ref).sha) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
+
+ context 'when the pipeline was successfull' do
+ it 'displays so on the badge' do
+ job.success
+
+ visit pipeline_project_badges_path(project, ref: ref, format: :svg)
+
+ expect(page.status_code).to eq(200)
+ expect_badge('passed')
+ end
+ end
+
+ context 'when the pipeline failed' do
+ it 'shows displays so on the badge' do
+ job.drop
+
+ visit pipeline_project_badges_path(project, ref: ref, format: :svg)
+
+ expect(page.status_code).to eq(200)
+ expect_badge('failed')
+ end
+ end
+
+ context 'when the pipeline is running' do
+ it 'shows displays so on the badge' do
+ create(:ci_build, pipeline: pipeline, name: 'second build', status_event: 'run')
+
+ visit pipeline_project_badges_path(project, ref: ref, format: :svg)
+
+ expect(page.status_code).to eq(200)
+ expect_badge('running')
+ end
+ end
+
+ context 'when a new pipeline is created' do
+ it 'shows a fresh badge' do
+ visit pipeline_project_badges_path(project, ref: ref, format: :svg)
+
+ expect(page.status_code).to eq(200)
+ expect(page.response_headers['Cache-Control']).to include 'no-cache'
+ end
+ end
+
+ def expect_badge(status)
+ svg = Nokogiri::XML.parse(page.body)
+ expect(page.response_headers['Content-Type']).to include('image/svg+xml')
+ expect(svg.at(%Q{text:contains("#{status}")})).to be_truthy
+ end
+ end
+end
diff --git a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb
index 53c5a52ce3a..1160f674974 100644
--- a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb
+++ b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true, js: true do
+feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', js: true do
include TreeHelper
let(:project) { create(:project, :public, :repository) }
@@ -13,14 +13,14 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
end
def visit_blob(fragment = nil)
- visit namespace_project_blob_path(project.namespace, project, tree_join('master', path), anchor: fragment)
+ visit project_blob_path(project, tree_join('master', path), anchor: fragment)
end
describe 'Click "Permalink" button' do
it 'works with no initial line number fragment hash' do
visit_blob
- expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(namespace_project_blob_path(project.namespace, project, tree_join(sha, path))))
+ expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path))))
end
it 'maintains intitial fragment hash' do
@@ -28,7 +28,7 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
visit_blob(fragment)
- expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(namespace_project_blob_path(project.namespace, project, tree_join(sha, path), anchor: fragment)))
+ expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: fragment)))
end
it 'changes fragment hash if line number clicked' do
@@ -39,7 +39,7 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
find('#L3').click
find("##{ending_fragment}").click
- expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(namespace_project_blob_path(project.namespace, project, tree_join(sha, path), anchor: ending_fragment)))
+ expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: ending_fragment)))
end
it 'with initial fragment hash, changes fragment hash if line number clicked' do
@@ -51,15 +51,15 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
find('#L3').click
find("##{ending_fragment}").click
- expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(namespace_project_blob_path(project.namespace, project, tree_join(sha, path), anchor: ending_fragment)))
+ expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: ending_fragment)))
end
end
- describe 'Click "Annotate" button' do
+ describe 'Click "Blame" button' do
it 'works with no initial line number fragment hash' do
visit_blob
- expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(namespace_project_blame_path(project.namespace, project, tree_join('master', path))))
+ expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path))))
end
it 'maintains intitial fragment hash' do
@@ -67,7 +67,7 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
visit_blob(fragment)
- expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(namespace_project_blame_path(project.namespace, project, tree_join('master', path), anchor: fragment)))
+ expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: fragment)))
end
it 'changes fragment hash if line number clicked' do
@@ -78,7 +78,7 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
find('#L3').click
find("##{ending_fragment}").click
- expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(namespace_project_blame_path(project.namespace, project, tree_join('master', path), anchor: ending_fragment)))
+ expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: ending_fragment)))
end
it 'with initial fragment hash, changes fragment hash if line number clicked' do
@@ -90,7 +90,7 @@ feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true,
find('#L3').click
find("##{ending_fragment}").click
- expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(namespace_project_blame_path(project.namespace, project, tree_join('master', path), anchor: ending_fragment)))
+ expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: ending_fragment)))
end
end
end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 71ffa352f80..3d465e709b9 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'File blob', :js, feature: true do
- let(:project) { create(:project, :public) }
+feature 'File blob', :js do
+ let(:project) { create(:project, :public, :repository) }
def visit_blob(path, anchor: nil, ref: 'master')
- visit namespace_project_blob_path(project.namespace, project, File.join(ref, path), anchor: anchor)
+ visit project_blob_path(project, File.join(ref, path), anchor: anchor)
wait_for_requests
end
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index d0bc032ee93..9855cfd85c4 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-feature 'Editing file blob', feature: true, js: true do
+feature 'Editing file blob', js: true do
include TreeHelper
- let(:project) { create(:project, :public, :test_repo) }
+ let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
let(:branch) { 'master' }
let(:file_path) { project.repository.ls_files(project.repository.root_ref)[1] }
@@ -14,7 +14,7 @@ feature 'Editing file blob', feature: true, js: true do
before do
project.team << [user, role]
- gitlab_sign_in(user)
+ sign_in(user)
end
def edit_and_commit
@@ -26,7 +26,7 @@ feature 'Editing file blob', feature: true, js: true do
context 'from MR diff' do
before do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit diffs_project_merge_request_path(project, merge_request)
edit_and_commit
end
@@ -37,7 +37,7 @@ feature 'Editing file blob', feature: true, js: true do
context 'from blob file path' do
before do
- visit namespace_project_blob_path(project.namespace, project, tree_join(branch, file_path))
+ visit project_blob_path(project, tree_join(branch, file_path))
edit_and_commit
end
@@ -55,7 +55,7 @@ feature 'Editing file blob', feature: true, js: true do
before do
project.team << [user, :developer]
- visit namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path))
+ visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'redirects to sign in and returns' do
@@ -63,7 +63,7 @@ feature 'Editing file blob', feature: true, js: true do
gitlab_sign_in(user)
- expect(page).to have_current_path(namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path)))
+ expect(page).to have_current_path(project_edit_blob_path(project, tree_join(branch, file_path)))
end
end
@@ -71,7 +71,7 @@ feature 'Editing file blob', feature: true, js: true do
let(:user) { create(:user) }
before do
- visit namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path))
+ visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'redirects to sign in and returns' do
@@ -79,7 +79,7 @@ feature 'Editing file blob', feature: true, js: true do
gitlab_sign_in(user)
- expect(page).to have_current_path(namespace_project_blob_path(project.namespace, project, tree_join(branch, file_path)))
+ expect(page).to have_current_path(project_blob_path(project, tree_join(branch, file_path)))
end
end
end
@@ -92,23 +92,23 @@ feature 'Editing file blob', feature: true, js: true do
project.team << [user, :developer]
project.repository.add_branch(user, protected_branch, 'master')
create(:protected_branch, project: project, name: protected_branch)
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'on some branch' do
before do
- visit namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path))
+ visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'shows blob editor with same branch' do
- expect(page).to have_current_path(namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path)))
+ expect(page).to have_current_path(project_edit_blob_path(project, tree_join(branch, file_path)))
expect(find('.js-branch-name').value).to eq(branch)
end
end
context 'with protected branch' do
before do
- visit namespace_project_edit_blob_path(project.namespace, project, tree_join(protected_branch, file_path))
+ visit project_edit_blob_path(project, tree_join(protected_branch, file_path))
end
it 'shows blob editor with patch branch' do
@@ -122,12 +122,12 @@ feature 'Editing file blob', feature: true, js: true do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path))
+ sign_in(user)
+ visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'shows blob editor with same branch' do
- expect(page).to have_current_path(namespace_project_edit_blob_path(project.namespace, project, tree_join(branch, file_path)))
+ expect(page).to have_current_path(project_edit_blob_path(project, tree_join(branch, file_path)))
expect(find('.js-branch-name').value).to eq(branch)
end
end
diff --git a/spec/features/projects/blobs/shortcuts_blob_spec.rb b/spec/features/projects/blobs/shortcuts_blob_spec.rb
index 30e2d587267..1e3080fa319 100644
--- a/spec/features/projects/blobs/shortcuts_blob_spec.rb
+++ b/spec/features/projects/blobs/shortcuts_blob_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Blob shortcuts', feature: true do
+feature 'Blob shortcuts' do
include TreeHelper
let(:project) { create(:project, :public, :repository) }
let(:path) { project.repository.ls_files(project.repository.root_ref)[0] }
@@ -12,7 +12,7 @@ feature 'Blob shortcuts', feature: true do
end
def visit_blob(fragment = nil)
- visit namespace_project_blob_path(project.namespace, project, tree_join('master', path), anchor: fragment)
+ visit project_blob_path(project, tree_join('master', path), anchor: fragment)
end
describe 'pressing "y"' do
@@ -21,7 +21,7 @@ feature 'Blob shortcuts', feature: true do
find('body').native.send_key('y')
- expect(page).to have_current_path(get_absolute_url(namespace_project_blob_path(project.namespace, project, tree_join(sha, path))), url: true)
+ expect(page).to have_current_path(get_absolute_url(project_blob_path(project, tree_join(sha, path))), url: true)
end
it 'maintains fragment hash when redirecting' do
@@ -30,7 +30,7 @@ feature 'Blob shortcuts', feature: true do
find('body').native.send_key('y')
- expect(page).to have_current_path(get_absolute_url(namespace_project_blob_path(project.namespace, project, tree_join(sha, path), anchor: fragment)), url: true)
+ expect(page).to have_current_path(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: fragment)), url: true)
end
end
end
diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb
index d8c4d475a2c..ad06cee4e81 100644
--- a/spec/features/projects/branches/download_buttons_spec.rb
+++ b/spec/features/projects/branches/download_buttons_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Download buttons in branches page', feature: true do
+feature 'Download buttons in branches page' do
given(:user) { create(:user) }
given(:role) { :developer }
given(:status) { 'success' }
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
given(:pipeline) do
create(:ci_pipeline,
@@ -22,20 +22,18 @@ feature 'Download buttons in branches page', feature: true do
end
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
end
describe 'when checking branches' do
context 'with artifacts' do
before do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
end
scenario 'shows download artifacts button' do
- href = latest_succeeded_namespace_project_artifacts_path(
- project.namespace, project, 'binary-encoding/download',
- job: 'build')
+ href = latest_succeeded_project_artifacts_path(project, 'binary-encoding/download', job: 'build')
expect(page).to have_link "Download '#{build.name}'", href: href
end
diff --git a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb
index 406fa52e723..0be434a567b 100644
--- a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb
+++ b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'New Branch Ref Dropdown', :js, :feature do
+describe 'New Branch Ref Dropdown', :js do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:toggle) { find('.create-from .dropdown-menu-toggle') }
before do
project.add_master(user)
- gitlab_sign_in(user)
- visit new_namespace_project_branch_path(project.namespace, project)
+ sign_in(user)
+ visit new_project_branch_path(project)
end
it 'filters a list of branches and tags' do
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index 2570ae60cef..b7ceac79c40 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe 'Branches', feature: true do
+describe 'Branches' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:repository) { project.repository }
def set_protected_branch_name(branch_name)
@@ -19,24 +19,61 @@ describe 'Branches', feature: true do
describe 'Initial branches page' do
it 'shows all the branches' do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
- repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
- expect(page).to have_content("Protected branches can be managed in project settings")
+ repository.branches_sorted_by(:name).first(20).each do |branch|
+ expect(page).to have_content("#{branch.name}")
+ end
+ end
+
+ it 'sorts the branches by name' do
+ visit project_branches_path(project)
+
+ click_button "Last updated" # Open sorting dropdown
+ click_link "Name"
+
+ sorted = repository.branches_sorted_by(:name).first(20).map do |branch|
+ Regexp.escape(branch.name)
+ end
+ expect(page).to have_content(/#{sorted.join(".*")}/)
+ end
+
+ it 'sorts the branches by last updated' do
+ visit project_branches_path(project)
+
+ click_button "Last updated" # Open sorting dropdown
+ click_link "Last updated"
+
+ sorted = repository.branches_sorted_by(:updated_desc).first(20).map do |branch|
+ Regexp.escape(branch.name)
+ end
+ expect(page).to have_content(/#{sorted.join(".*")}/)
+ end
+
+ it 'sorts the branches by oldest updated' do
+ visit project_branches_path(project)
+
+ click_button "Last updated" # Open sorting dropdown
+ click_link "Oldest updated"
+
+ sorted = repository.branches_sorted_by(:updated_asc).first(20).map do |branch|
+ Regexp.escape(branch.name)
+ end
+ expect(page).to have_content(/#{sorted.join(".*")}/)
end
it 'avoids a N+1 query in branches index' do
- control_count = ActiveRecord::QueryRecorder.new { visit namespace_project_branches_path(project.namespace, project) }.count
+ control_count = ActiveRecord::QueryRecorder.new { visit project_branches_path(project) }.count
%w(one two three four five).each { |ref| repository.add_branch(user, ref, 'master') }
- expect { visit namespace_project_branches_path(project.namespace, project) }.not_to exceed_query_limit(control_count)
+ expect { visit project_branches_path(project) }.not_to exceed_query_limit(control_count)
end
end
describe 'Find branches' do
it 'shows filtered branches', js: true do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
@@ -48,7 +85,7 @@ describe 'Branches', feature: true do
describe 'Delete unprotected branch' do
it 'removes branch after confirmation', js: true do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
fill_in 'branch-search', with: 'fix'
@@ -66,7 +103,7 @@ describe 'Branches', feature: true do
describe 'Delete protected branch' do
before do
project.add_user(user, :master)
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('fix')
click_on "Protect"
@@ -76,7 +113,7 @@ describe 'Branches', feature: true do
end
it 'does not allow devleoper to removes protected branch', js: true do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
@@ -92,9 +129,17 @@ describe 'Branches', feature: true do
project.team << [user, :master]
end
+ describe 'Initial branches page' do
+ it 'shows description for admin' do
+ visit project_branches_path(project)
+
+ expect(page).to have_content("Protected branches can be managed in project settings")
+ end
+ end
+
describe 'Delete protected branch' do
before do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('fix')
click_on "Protect"
@@ -103,7 +148,7 @@ describe 'Branches', feature: true do
end
it 'removes branch after modal confirmation', js: true do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
@@ -126,7 +171,7 @@ describe 'Branches', feature: true do
context 'logged out' do
before do
- visit namespace_project_branches_path(project.namespace, project)
+ visit project_branches_path(project)
end
it 'does not show merge request button' do
diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb
index e5b1f95f2b9..740331fe42a 100644
--- a/spec/features/projects/commit/builds_spec.rb
+++ b/spec/features/projects/commit/builds_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
feature 'project commit pipelines', js: true do
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
background do
user = create(:user)
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when no builds triggered yet' do
@@ -17,7 +17,7 @@ feature 'project commit pipelines', js: true do
end
scenario 'user views commit pipelines page' do
- visit pipelines_namespace_project_commit_path(project.namespace, project, project.commit.sha)
+ visit pipelines_project_commit_path(project, project.commit.sha)
page.within('.table-holder') do
expect(page).to have_content project.pipelines[0].status # pipeline status
diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb
index 0d3fa72fbf5..7086f56bb1b 100644
--- a/spec/features/projects/commit/cherry_pick_spec.rb
+++ b/spec/features/projects/commit/cherry_pick_spec.rb
@@ -3,14 +3,14 @@ require 'spec_helper'
describe 'Cherry-pick Commits' do
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:project, :repository, namespace: group) }
let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
let(:master_pickable_merge) { project.commit('e56497bb5f03a90a51293fc6d516788730953899') }
before do
sign_in(user)
project.team << [user, :master]
- visit namespace_project_commit_path(project.namespace, project, master_pickable_commit.id)
+ visit project_commit_path(project, master_pickable_commit.id)
end
context "I cherry-pick a commit" do
@@ -43,7 +43,7 @@ describe 'Cherry-pick Commits' do
uncheck 'create_merge_request'
click_button 'Cherry-pick'
end
- visit namespace_project_commit_path(project.namespace, project, master_pickable_commit.id)
+ visit project_commit_path(project, master_pickable_commit.id)
find("a[href='#modal-cherry-pick-commit']").click
page.within('#modal-cherry-pick-commit') do
uncheck 'create_merge_request'
diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
index 570a7ae7b16..2ef74e8857c 100644
--- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb
+++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'Mini Pipeline Graph in Commit View', :js, :feature do
+feature 'Mini Pipeline Graph in Commit View', :js do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when commit has pipelines' do
@@ -22,7 +22,7 @@ feature 'Mini Pipeline Graph in Commit View', :js, :feature do
before do
build.run
- visit namespace_project_commit_path(project.namespace, project, project.commit.id)
+ visit project_commit_path(project, project.commit.id)
end
it 'should display a mini pipeline graph' do
@@ -43,7 +43,7 @@ feature 'Mini Pipeline Graph in Commit View', :js, :feature do
context 'when commit does not have pipelines' do
before do
- visit namespace_project_commit_path(project.namespace, project, project.commit.id)
+ visit project_commit_path(project, project.commit.id)
end
it 'should not display a mini pipeline graph' do
diff --git a/spec/features/projects/commit/rss_spec.rb b/spec/features/projects/commit/rss_spec.rb
index f7548a56984..db958346f06 100644
--- a/spec/features/projects/commit/rss_spec.rb
+++ b/spec/features/projects/commit/rss_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
feature 'Project Commits RSS' do
+ let(:user) { create(:user) }
let(:project) { create(:project, :repository, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:path) { namespace_project_commits_path(project.namespace, project, :master) }
+ let(:path) { project_commits_path(project, :master) }
context 'when signed in' do
before do
- user = create(:user)
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb
index 4743d69fb75..82d73fe8531 100644
--- a/spec/features/projects/compare_spec.rb
+++ b/spec/features/projects/compare_spec.rb
@@ -2,12 +2,12 @@ require "spec_helper"
describe "Compare", js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_compare_index_path(project.namespace, project, from: "master", to: "master")
+ sign_in user
+ visit project_compare_index_path(project, from: "master", to: "master")
end
describe "branches" do
diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb
index a31960639fe..2d1a9b931b5 100644
--- a/spec/features/projects/deploy_keys_spec.rb
+++ b/spec/features/projects/deploy_keys_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe 'Project deploy keys', :js, :feature do
+describe 'Project deploy keys', :js do
let(:user) { create(:user) }
let(:project) { create(:project_empty_repo) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'removing key' do
@@ -15,7 +15,7 @@ describe 'Project deploy keys', :js, :feature do
end
it 'removes association between project and deploy key' do
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
page.within(find('.deploy-keys')) do
expect(page).to have_selector('.deploy-keys li', count: 1)
diff --git a/spec/features/projects/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/developer_views_empty_project_instructions_spec.rb
index a943f1e6a08..7145e286229 100644
--- a/spec/features/projects/developer_views_empty_project_instructions_spec.rb
+++ b/spec/features/projects/developer_views_empty_project_instructions_spec.rb
@@ -1,13 +1,13 @@
require 'rails_helper'
-feature 'Developer views empty project instructions', feature: true do
+feature 'Developer views empty project instructions' do
let(:project) { create(:empty_project, :empty_repo) }
let(:developer) { create(:user) }
background do
project.team << [developer, :developer]
- gitlab_sign_in(developer)
+ sign_in(developer)
end
context 'without an SSH key' do
@@ -47,7 +47,7 @@ feature 'Developer views empty project instructions', feature: true do
end
def visit_project
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
def select_protocol(protocol)
diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb
index 48b7f1e0f34..bc102895aaf 100644
--- a/spec/features/projects/diffs/diff_show_spec.rb
+++ b/spec/features/projects/diffs/diff_show_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Diff file viewer', :js, feature: true do
+feature 'Diff file viewer', :js do
let(:project) { create(:project, :public, :repository) }
def visit_commit(sha, anchor: nil)
- visit namespace_project_commit_path(project.namespace, project, sha, anchor: anchor)
+ visit project_commit_path(project, sha, anchor: anchor)
wait_for_requests
end
@@ -110,6 +110,10 @@ feature 'Diff file viewer', :js, feature: true do
context 'binary file that appears to be text in the first 1024 bytes' do
before do
+ # The file we're visiting is smaller than 10 KB and we want it collapsed
+ # so we need to disable the size increase feature.
+ stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
+
visit_commit('7b1cf4336b528e0f3d1d140ee50cafdbc703597c')
end
diff --git a/spec/features/projects/edit_spec.rb b/spec/features/projects/edit_spec.rb
index ca202b95a44..4b5436027f9 100644
--- a/spec/features/projects/edit_spec.rb
+++ b/spec/features/projects/edit_spec.rb
@@ -1,14 +1,14 @@
require 'rails_helper'
-feature 'Project edit', feature: true, js: true do
+feature 'Project edit', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
end
context 'feature visibility' do
@@ -20,7 +20,7 @@ feature 'Project edit', feature: true, js: true do
end
context 'given project with merge_requests_disabled access level' do
- let(:project) { create(:project, :merge_requests_disabled) }
+ let(:project) { create(:empty_project, :merge_requests_disabled) }
it 'hides merge requests section' do
expect(page).to have_selector('.merge-requests-feature', visible: false)
@@ -36,7 +36,7 @@ feature 'Project edit', feature: true, js: true do
end
context 'given project with builds_disabled access level' do
- let(:project) { create(:project, :builds_disabled) }
+ let(:project) { create(:empty_project, :builds_disabled) }
it 'hides builds select section' do
expect(page).to have_selector('.builds-feature', visible: false)
diff --git a/spec/features/projects/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb
index b48dcf6c774..82a722c5960 100644
--- a/spec/features/projects/environments/environment_metrics_spec.rb
+++ b/spec/features/projects/environments/environment_metrics_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Environment > Metrics', :feature do
+feature 'Environment > Metrics' do
include PrometheusHelpers
given(:user) { create(:user) }
@@ -15,7 +15,7 @@ feature 'Environment > Metrics', :feature do
create(:deployment, environment: environment, deployable: build)
stub_all_prometheus_requests(environment.slug)
- gitlab_sign_in(user)
+ sign_in(user)
visit_environment(environment)
end
@@ -27,13 +27,11 @@ feature 'Environment > Metrics', :feature do
scenario 'shows metrics' do
click_link('See metrics')
- expect(page).to have_css('svg.prometheus-graph')
+ expect(page).to have_css('div#prometheus-graphs')
end
end
def visit_environment(environment)
- visit namespace_project_environment_path(environment.project.namespace,
- environment.project,
- environment)
+ visit project_environment_path(environment.project, environment)
end
end
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index 7d565555f1f..c6b7e611a5c 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Environment', :feature do
+feature 'Environment' do
given(:project) { create(:empty_project) }
given(:user) { create(:user) }
given(:role) { :developer }
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
end
@@ -114,7 +114,7 @@ feature 'Environment', :feature do
before do
# Stub #terminals as it causes js-enabled feature specs to render the page incorrectly
allow_any_instance_of(Environment).to receive(:terminals) { nil }
- visit terminal_namespace_project_environment_path(project.namespace, project, environment)
+ visit terminal_project_environment_path(project, environment)
end
it 'displays a web terminal' do
@@ -194,9 +194,7 @@ feature 'Environment', :feature do
name: 'staging-1.0/review',
state: :available)
- visit folder_namespace_project_environments_path(project.namespace,
- project,
- id: 'staging-1.0')
+ visit folder_project_environments_path(project, id: 'staging-1.0')
end
it 'renders a correct environment folder' do
@@ -207,7 +205,7 @@ feature 'Environment', :feature do
end
feature 'auto-close environment when branch is deleted' do
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
given!(:environment) do
create(:environment, :with_review_app, project: project,
@@ -221,7 +219,7 @@ feature 'Environment', :feature do
end
scenario 'user deletes the branch with running environment' do
- visit namespace_project_branches_path(project.namespace, project, search: 'feature')
+ visit project_branches_path(project, search: 'feature')
remove_branch_with_hooks(project, user, 'feature') do
page.within('.js-branch-feature') { find('a.btn-remove').click }
@@ -249,12 +247,10 @@ feature 'Environment', :feature do
end
def visit_environment(environment)
- visit namespace_project_environment_path(environment.project.namespace,
- environment.project,
- environment)
+ visit project_environment_path(environment.project, environment)
end
def have_terminal_button
- have_link(nil, href: terminal_namespace_project_environment_path(project.namespace, project, environment))
+ have_link(nil, href: terminal_project_environment_path(project, environment))
end
end
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 83883dba0ba..36cf307fbe2 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Environments page', :feature, :js do
+feature 'Environments page', :js do
given(:project) { create(:empty_project) }
given(:user) { create(:user) }
given(:role) { :developer }
background do
project.team << [user, role]
- gitlab_sign_in(user)
+ sign_in(user)
end
given!(:environment) { }
@@ -29,7 +29,7 @@ feature 'Environments page', :feature, :js do
describe 'in available tab page' do
it 'should show one environment' do
- visit namespace_project_environments_path(project.namespace, project, scope: 'available')
+ visit project_environments_path(project, scope: 'available')
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
end
@@ -37,7 +37,7 @@ feature 'Environments page', :feature, :js do
describe 'in stopped tab page' do
it 'should show no environments' do
- visit namespace_project_environments_path(project.namespace, project, scope: 'stopped')
+ visit project_environments_path(project, scope: 'stopped')
expect(page).to have_css('.environments-container')
expect(page).to have_content('You don\'t have any environments right now')
end
@@ -49,7 +49,7 @@ feature 'Environments page', :feature, :js do
describe 'in available tab page' do
it 'should show no environments' do
- visit namespace_project_environments_path(project.namespace, project, scope: 'available')
+ visit project_environments_path(project, scope: 'available')
expect(page).to have_css('.environments-container')
expect(page).to have_content('You don\'t have any environments right now')
end
@@ -57,7 +57,7 @@ feature 'Environments page', :feature, :js do
describe 'in stopped tab page' do
it 'should show one environment' do
- visit namespace_project_environments_path(project.namespace, project, scope: 'stopped')
+ visit project_environments_path(project, scope: 'stopped')
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
end
@@ -111,7 +111,7 @@ feature 'Environments page', :feature, :js do
end
context 'with deployments' do
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
given(:deployment) do
create(:deployment, environment: environment,
@@ -151,7 +151,7 @@ feature 'Environments page', :feature, :js do
find('.js-dropdown-play-icon-container').click
expect(page).to have_content(action.name.humanize)
- expect { find('.js-manual-action-link').click }
+ expect { find('.js-manual-action-link').trigger('click') }
.not_to change { Ci::Pipeline.count }
end
@@ -277,10 +277,10 @@ feature 'Environments page', :feature, :js do
end
def have_terminal_button
- have_link(nil, href: terminal_namespace_project_environment_path(project.namespace, project, environment))
+ have_link(nil, href: terminal_project_environment_path(project, environment))
end
def visit_environments(project)
- visit namespace_project_environments_path(project.namespace, project)
+ visit project_environments_path(project)
end
end
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index db2790a4bce..37fa61d038e 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'Edit Project Settings', feature: true do
+describe 'Edit Project Settings' do
let(:member) { create(:user) }
- let!(:project) { create(:project, :public, path: 'gitlab', name: 'sample') }
+ let!(:project) { create(:project, :public, :repository) }
let!(:issue) { create(:issue, project: project) }
let(:non_member) { create(:user) }
describe 'project features visibility selectors', js: true do
before do
project.team << [member, :master]
- gitlab_sign_in(member)
+ sign_in(member)
end
tools = { builds: "pipelines", issues: "issues", wiki: "wiki", snippets: "snippets", merge_requests: "merge_requests" }
@@ -17,7 +17,7 @@ describe 'Edit Project Settings', feature: true do
tools.each do |tool_name, shortcut_name|
describe "feature #{tool_name}" do
it 'toggles visibility' do
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
select 'Disabled', from: "project_project_feature_attributes_#{tool_name}_access_level"
click_button 'Save changes'
@@ -39,20 +39,31 @@ describe 'Edit Project Settings', feature: true do
end
end
- context "When external issue tracker is enabled" do
- it "does not hide issues tab" do
- project.project_feature.update(issues_access_level: ProjectFeature::DISABLED)
+ context 'When external issue tracker is enabled and issues enabled on project settings' do
+ it 'does not hide issues tab' do
allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
- expect(page).to have_selector(".shortcuts-issues")
+ expect(page).to have_selector('.shortcuts-issues')
+ end
+ end
+
+ context 'When external issue tracker is enabled and issues disabled on project settings' do
+ it 'hides issues tab' do
+ project.issues_enabled = false
+ project.save!
+ allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new)
+
+ visit project_path(project)
+
+ expect(page).not_to have_selector('.shortcuts-issues')
end
end
context "pipelines subtabs" do
it "shows builds when enabled" do
- visit namespace_project_pipelines_path(project.namespace, project)
+ visit project_pipelines_path(project)
expect(page).to have_selector(".shortcuts-builds")
end
@@ -60,7 +71,7 @@ describe 'Edit Project Settings', feature: true do
it "hides builds when disabled" do
allow(Ability).to receive(:allowed?).with(member, :read_builds, project).and_return(false)
- visit namespace_project_pipelines_path(project.namespace, project)
+ visit project_pipelines_path(project)
expect(page).not_to have_selector(".shortcuts-builds")
end
@@ -73,17 +84,17 @@ describe 'Edit Project Settings', feature: true do
let(:tools) do
{
- builds: namespace_project_job_path(project.namespace, project, job),
- issues: namespace_project_issues_path(project.namespace, project),
- wiki: namespace_project_wiki_path(project.namespace, project, :home),
- snippets: namespace_project_snippets_path(project.namespace, project),
- merge_requests: namespace_project_merge_requests_path(project.namespace, project)
+ builds: project_job_path(project, job),
+ issues: project_issues_path(project),
+ wiki: project_wiki_path(project, :home),
+ snippets: project_snippets_path(project),
+ merge_requests: project_merge_requests_path(project)
}
end
context 'normal user' do
before do
- gitlab_sign_in(member)
+ sign_in(member)
end
it 'renders 200 if tool is enabled' do
@@ -130,7 +141,7 @@ describe 'Edit Project Settings', feature: true do
context 'admin user' do
before do
non_member.update_attribute(:admin, true)
- gitlab_sign_in(non_member)
+ sign_in(non_member)
end
it 'renders 404 if feature is disabled' do
@@ -156,8 +167,8 @@ describe 'Edit Project Settings', feature: true do
describe 'repository visibility', js: true do
before do
project.team << [member, :master]
- gitlab_sign_in(member)
- visit edit_namespace_project_path(project.namespace, project)
+ sign_in(member)
+ visit edit_project_path(project)
end
it "disables repository related features" do
@@ -174,7 +185,7 @@ describe 'Edit Project Settings', feature: true do
click_button "Save changes"
wait_for_requests
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_content "Customize your workflow!"
end
@@ -187,7 +198,7 @@ describe 'Edit Project Settings', feature: true do
click_button "Save changes"
wait_for_requests
- visit activity_namespace_project_path(project.namespace, project)
+ visit activity_project_path(project)
page.within(".event-filter") do
expect(page).to have_selector("a", count: 2)
@@ -205,7 +216,7 @@ describe 'Edit Project Settings', feature: true do
expect(page).to have_content("Comments")
end
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
select "Disabled", from: "project_project_feature_attributes_merge_requests_access_level"
@@ -213,7 +224,7 @@ describe 'Edit Project Settings', feature: true do
expect(page).to have_content("Comments")
end
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
select "Disabled", from: "project_project_feature_attributes_repository_access_level"
@@ -221,14 +232,14 @@ describe 'Edit Project Settings', feature: true do
expect(page).not_to have_content("Comments")
end
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
end
def save_changes_and_check_activity_tab
click_button "Save changes"
wait_for_requests
- visit activity_namespace_project_path(project.namespace, project)
+ visit activity_project_path(project)
page.within(".event-filter") do
yield
@@ -238,12 +249,12 @@ describe 'Edit Project Settings', feature: true do
# Regression spec for https://gitlab.com/gitlab-org/gitlab-ce/issues/24056
describe 'project statistic visibility' do
- let!(:project) { create(:project, :private) }
+ let!(:project) { create(:empty_project, :private) }
before do
project.team << [member, :guest]
- gitlab_sign_in(member)
- visit namespace_project_path(project.namespace, project)
+ sign_in(member)
+ visit project_path(project)
end
it "does not show project statistic for guest" do
diff --git a/spec/features/projects/files/browse_files_spec.rb b/spec/features/projects/files/browse_files_spec.rb
index 2a82c3ac179..f62a9edd37e 100644
--- a/spec/features/projects/files/browse_files_spec.rb
+++ b/spec/features/projects/files/browse_files_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
-feature 'user browses project', feature: true, js: true do
- let(:project) { create(:project) }
+feature 'user browses project', js: true do
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_tree_path(project.namespace, project, project.default_branch)
+ sign_in(user)
+ visit project_tree_path(project, project.default_branch)
end
scenario "can see blame of '.gitignore'" do
click_link ".gitignore"
- click_link 'Annotate'
+ click_link 'Blame'
expect(page).to have_content "*.rb"
expect(page).to have_content "Dmitriy Zaporozhets"
diff --git a/spec/features/projects/files/creating_a_file_spec.rb b/spec/features/projects/files/creating_a_file_spec.rb
index 2a1cc01fe68..e13bf4b6089 100644
--- a/spec/features/projects/files/creating_a_file_spec.rb
+++ b/spec/features/projects/files/creating_a_file_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'User wants to create a file', feature: true do
- let(:project) { create(:project) }
+feature 'User wants to create a file' do
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
background do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_new_blob_path(project.namespace, project, project.default_branch)
+ sign_in user
+ visit project_new_blob_path(project, project.default_branch)
end
def submit_new_file(options)
@@ -30,11 +30,6 @@ feature 'User wants to create a file', feature: true do
expect(page).to have_content 'The file has been successfully created'
end
- scenario 'file name contains invalid characters' do
- submit_new_file(file_name: '\\')
- expect(page).to have_content 'Path can contain only'
- end
-
scenario 'file name contains directory traversal' do
submit_new_file(file_name: '../README.md')
expect(page).to have_content 'Path cannot include directory traversal'
diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb
index 4f1b8588462..cebb238dda1 100644
--- a/spec/features/projects/files/dockerfile_dropdown_spec.rb
+++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
require 'fileutils'
-feature 'User wants to add a Dockerfile file', feature: true do
+feature 'User wants to add a Dockerfile file' do
before do
user = create(:user)
- project = create(:project)
+ project = create(:project, :repository)
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
- visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: 'Dockerfile')
+ visit project_new_blob_path(project, 'master', file_name: 'Dockerfile')
end
scenario 'user can see Dockerfile dropdown' do
diff --git a/spec/features/projects/files/download_buttons_spec.rb b/spec/features/projects/files/download_buttons_spec.rb
index 60182bfebe9..d2382d55c0b 100644
--- a/spec/features/projects/files/download_buttons_spec.rb
+++ b/spec/features/projects/files/download_buttons_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Download buttons in files tree', feature: true do
+feature 'Download buttons in files tree' do
given(:user) { create(:user) }
given(:role) { :developer }
given(:status) { 'success' }
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
given(:pipeline) do
create(:ci_pipeline,
@@ -22,21 +22,18 @@ feature 'Download buttons in files tree', feature: true do
end
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
end
describe 'when files tree' do
context 'with artifacts' do
before do
- visit namespace_project_tree_path(
- project.namespace, project, project.default_branch)
+ visit project_tree_path(project, project.default_branch)
end
scenario 'shows download artifacts button' do
- href = latest_succeeded_namespace_project_artifacts_path(
- project.namespace, project, "#{project.default_branch}/download",
- job: 'build')
+ href = latest_succeeded_project_artifacts_path(project, "#{project.default_branch}/download", job: 'build')
expect(page).to have_link "Download '#{build.name}'", href: href
end
diff --git a/spec/features/projects/files/edit_file_soft_wrap_spec.rb b/spec/features/projects/files/edit_file_soft_wrap_spec.rb
index 6e361ac4312..c7e3f657639 100644
--- a/spec/features/projects/files/edit_file_soft_wrap_spec.rb
+++ b/spec/features/projects/files/edit_file_soft_wrap_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'User uses soft wrap whilst editing file', feature: true, js: true do
+feature 'User uses soft wrap whilst editing file', js: true do
before do
user = create(:user)
- project = create(:project)
+ project = create(:project, :repository)
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: 'test_file-name')
+ sign_in user
+ visit project_new_blob_path(project, 'master', file_name: 'test_file-name')
editor = find('.file-editor.code')
editor.click
editor.send_keys 'Touch water with paw then recoil in horror chase dog then
diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb
index e97ff5fded7..20be968e89f 100644
--- a/spec/features/projects/files/editing_a_file_spec.rb
+++ b/spec/features/projects/files/editing_a_file_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-feature 'User wants to edit a file', feature: true do
- let(:project) { create(:project) }
+feature 'User wants to edit a file' do
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:commit_params) do
{
@@ -17,8 +17,8 @@ feature 'User wants to edit a file', feature: true do
background do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_edit_blob_path(project.namespace, project,
+ sign_in user
+ visit project_edit_blob_path(project,
File.join(project.default_branch, '.gitignore'))
end
diff --git a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
index 83a837fba44..702b99de733 100644
--- a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
+++ b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'User views files page', feature: true do
+feature 'User views files page' do
let(:user) { create(:user) }
let(:project) { create(:forked_project_with_submodules) }
before do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_tree_path(project.namespace, project, project.repository.root_ref)
+ sign_in user
+ visit project_tree_path(project, project.repository.root_ref)
end
scenario 'user sees folders and submodules sorted together, followed by files' do
diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb
index 6a914820ac9..7f97fdb8cc9 100644
--- a/spec/features/projects/files/find_file_keyboard_spec.rb
+++ b/spec/features/projects/files/find_file_keyboard_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-feature 'Find file keyboard shortcuts', feature: true, js: true do
+feature 'Find file keyboard shortcuts', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
- visit namespace_project_find_file_path(project.namespace, project, project.repository.root_ref)
+ visit project_find_file_path(project, project.repository.root_ref)
wait_for_requests
end
diff --git a/spec/features/projects/files/find_files_spec.rb b/spec/features/projects/files/find_files_spec.rb
index 166ec5c921b..57d67b28920 100644
--- a/spec/features/projects/files/find_files_spec.rb
+++ b/spec/features/projects/files/find_files_spec.rb
@@ -1,29 +1,22 @@
require 'spec_helper'
-feature 'Find files button in the tree header', feature: true do
+feature 'Find files button in the tree header' do
given(:user) { create(:user) }
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :developer]
end
scenario 'project main screen' do
- visit namespace_project_path(
- project.namespace,
- project
- )
+ visit project_path(project)
expect(page).to have_selector('.tree-controls .shortcuts-find-file')
end
scenario 'project tree screen' do
- visit namespace_project_tree_path(
- project.namespace,
- project,
- project.default_branch
- )
+ visit project_tree_path(project, project.default_branch)
expect(page).to have_selector('.tree-controls .shortcuts-find-file')
end
diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb
index 7f02ec6b73d..e2044c9d5aa 100644
--- a/spec/features/projects/files/gitignore_dropdown_spec.rb
+++ b/spec/features/projects/files/gitignore_dropdown_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'User wants to add a .gitignore file', feature: true do
+feature 'User wants to add a .gitignore file' do
before do
user = create(:user)
- project = create(:project)
+ project = create(:project, :repository)
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: '.gitignore')
+ sign_in user
+ visit project_new_blob_path(project, 'master', file_name: '.gitignore')
end
scenario 'user can see .gitignore dropdown' do
diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
index f4b17c2518c..ab242b0b0b5 100644
--- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
+++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'User wants to add a .gitlab-ci.yml file', feature: true do
+feature 'User wants to add a .gitlab-ci.yml file' do
before do
user = create(:user)
- project = create(:project)
+ project = create(:project, :repository)
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: '.gitlab-ci.yml')
+ sign_in user
+ visit project_new_blob_path(project, 'master', file_name: '.gitlab-ci.yml')
end
scenario 'user can see .gitlab-ci.yml dropdown' do
diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
index 7daf016dd22..95af263bcac 100644
--- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb
+++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
-feature 'project owner creates a license file', feature: true, js: true do
+feature 'project owner creates a license file', js: true do
let(:project_master) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
background do
project.repository.delete_file(project_master, 'LICENSE',
message: 'Remove LICENSE', branch_name: 'master')
project.team << [project_master, :master]
- gitlab_sign_in(project_master)
- visit namespace_project_path(project.namespace, project)
+ sign_in(project_master)
+ visit project_path(project)
end
scenario 'project master creates a license file manually from a template' do
- visit namespace_project_tree_path(project.namespace, project, project.repository.root_ref)
+ visit project_tree_path(project, project.repository.root_ref)
find('.add-to-tree').click
click_link 'New file'
@@ -30,7 +30,7 @@ feature 'project owner creates a license file', feature: true, js: true do
click_button 'Commit changes'
expect(current_path).to eq(
- namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
+ project_blob_path(project, 'master/LICENSE'))
expect(page).to have_content('MIT License')
expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
@@ -40,7 +40,7 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(page).to have_content('New file')
expect(current_path).to eq(
- namespace_project_new_blob_path(project.namespace, project, 'master'))
+ project_new_blob_path(project, 'master'))
expect(find('#file_name').value).to eq('LICENSE')
expect(page).to have_selector('.license-selector')
@@ -54,7 +54,7 @@ feature 'project owner creates a license file', feature: true, js: true do
click_button 'Commit changes'
expect(current_path).to eq(
- namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
+ project_blob_path(project, 'master/LICENSE'))
expect(page).to have_content('MIT License')
expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index eab19d52030..1f4b3763b40 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -1,21 +1,21 @@
require 'spec_helper'
-feature 'project owner sees a link to create a license file in empty project', feature: true, js: true do
+feature 'project owner sees a link to create a license file in empty project', js: true do
let(:project_master) { create(:user) }
let(:project) { create(:empty_project) }
background do
project.team << [project_master, :master]
- gitlab_sign_in(project_master)
+ sign_in(project_master)
end
scenario 'project master creates a license file from a template' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
click_link 'Create empty bare repository'
click_on 'LICENSE'
expect(page).to have_content('New file')
expect(current_path).to eq(
- namespace_project_new_blob_path(project.namespace, project, 'master'))
+ project_new_blob_path(project, 'master'))
expect(find('#file_name').value).to eq('LICENSE')
expect(page).to have_selector('.license-selector')
@@ -31,7 +31,7 @@ feature 'project owner sees a link to create a license file in empty project', f
click_button 'Commit changes'
expect(current_path).to eq(
- namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
+ project_blob_path(project, 'master/LICENSE'))
expect(page).to have_content('MIT License')
expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb
index 028a0919640..48003eeaa87 100644
--- a/spec/features/projects/files/template_type_dropdown_spec.rb
+++ b/spec/features/projects/files/template_type_dropdown_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
feature 'Template type dropdown selector', js: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'editing a non-matching file' do
@@ -31,7 +31,7 @@ feature 'Template type dropdown selector', js: true do
context 'editing a matching file' do
before do
- visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, 'LICENSE'))
+ visit project_edit_blob_path(project, File.join(project.default_branch, 'LICENSE'))
end
scenario 'displayed' do
@@ -61,7 +61,7 @@ feature 'Template type dropdown selector', js: true do
context 'creating a matching file' do
before do
- visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: '.gitignore')
+ visit project_new_blob_path(project, 'master', file_name: '.gitignore')
end
scenario 'is displayed' do
@@ -79,7 +79,7 @@ feature 'Template type dropdown selector', js: true do
context 'creating a file' do
before do
- visit namespace_project_new_blob_path(project.namespace, project, project.default_branch)
+ visit project_new_blob_path(project, project.default_branch)
end
scenario 'type selector is shown' do
@@ -129,7 +129,7 @@ def check_type_selector_toggle_text(template_type)
end
def create_and_edit_file(file_name)
- visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: file_name)
+ visit project_new_blob_path(project, 'master', file_name: file_name)
click_button "Commit changes"
- visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, file_name))
+ visit project_edit_blob_path(project, File.join(project.default_branch, file_name))
end
diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb
index 4ccd123f46e..4238d25e9ee 100644
--- a/spec/features/projects/files/undo_template_spec.rb
+++ b/spec/features/projects/files/undo_template_spec.rb
@@ -1,17 +1,17 @@
require 'spec_helper'
feature 'Template Undo Button', js: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'editing a matching file and applying a template' do
before do
- visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, "LICENSE"))
+ visit project_edit_blob_path(project, File.join(project.default_branch, "LICENSE"))
select_file_template('.js-license-selector', 'Apache License 2.0')
end
@@ -22,7 +22,7 @@ feature 'Template Undo Button', js: true do
context 'creating a non-matching file' do
before do
- visit namespace_project_new_blob_path(project.namespace, project, 'master')
+ visit project_new_blob_path(project, 'master')
select_file_template_type('LICENSE')
select_file_template('.js-license-selector', 'Apache License 2.0')
end
diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb
index aa4ed217a34..b63e5ae46ee 100644
--- a/spec/features/projects/gfm_autocomplete_load_spec.rb
+++ b/spec/features/projects/gfm_autocomplete_load_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe 'GFM autocomplete loading', feature: true, js: true do
- let(:project) { create(:project) }
+describe 'GFM autocomplete loading', js: true do
+ let(:project) { create(:empty_project) }
before do
- gitlab_sign_in :admin
+ sign_in(create(:admin))
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
it 'does not load on project#show' do
@@ -14,7 +14,7 @@ describe 'GFM autocomplete loading', feature: true, js: true do
end
it 'loads on new issue page' do
- visit new_namespace_project_issue_path(project.namespace, project)
+ visit new_project_issue_path(project)
expect(evaluate_script('gl.GfmAutoComplete.dataSources')).not_to eq({})
end
diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb
index 52dba044364..30800aae468 100644
--- a/spec/features/projects/group_links_spec.rb
+++ b/spec/features/projects/group_links_spec.rb
@@ -1,20 +1,20 @@
require 'spec_helper'
-feature 'Project group links', :feature, :js do
+feature 'Project group links', :js do
include Select2Helper
let(:master) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let!(:group) { create(:group) }
background do
project.add_master(master)
- gitlab_sign_in(master)
+ sign_in(master)
end
context 'setting an expiration date for a group link' do
before do
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
click_on 'share-with-group-tab'
@@ -35,7 +35,7 @@ feature 'Project group links', :feature, :js do
context 'nested group project' do
let!(:nested_group) { create(:group, parent: group) }
let!(:another_group) { create(:group) }
- let!(:project) { create(:project, namespace: nested_group) }
+ let!(:project) { create(:empty_project, namespace: nested_group) }
background do
group.add_master(master)
@@ -43,7 +43,7 @@ feature 'Project group links', :feature, :js do
end
it 'does not show ancestors', :nested_groups do
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
click_on 'share-with-group-tab'
click_link 'Search for a group'
@@ -61,7 +61,7 @@ feature 'Project group links', :feature, :js do
group.add_owner(master)
group_two.add_owner(master)
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
execute_script 'GroupsSelect.PER_PAGE = 1;'
open_select2 '#link_group_id'
end
diff --git a/spec/features/projects/guest_navigation_menu_spec.rb b/spec/features/projects/guest_navigation_menu_spec.rb
index e1f7f06c113..1c5f89fa898 100644
--- a/spec/features/projects/guest_navigation_menu_spec.rb
+++ b/spec/features/projects/guest_navigation_menu_spec.rb
@@ -7,11 +7,11 @@ describe 'Guest navigation menu' do
before do
project.team << [guest, :guest]
- gitlab_sign_in(guest)
+ sign_in(guest)
end
it 'shows allowed tabs only' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
within('.layout-nav') do
expect(page).to have_content 'Project'
@@ -25,7 +25,7 @@ describe 'Guest navigation menu' do
end
it 'does not show fork button' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
within('.count-buttons') do
expect(page).not_to have_link 'Fork'
@@ -33,7 +33,7 @@ describe 'Guest navigation menu' do
end
it 'does not show clone path' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
within('.project-repo-buttons') do
expect(page).not_to have_selector '.project-clone-holder'
@@ -49,7 +49,7 @@ describe 'Guest navigation menu' do
end
it 'does not show the project file list landing page' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).not_to have_selector '.project-stats'
expect(page).not_to have_selector '.project-last-commit'
@@ -58,7 +58,7 @@ describe 'Guest navigation menu' do
end
it 'shows the customize workflow when issues and wiki are disabled' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_selector '.project-show-customize_workflow'
end
@@ -66,7 +66,7 @@ describe 'Guest navigation menu' do
it 'shows the wiki when enabled' do
project.project_feature.update!(wiki_access_level: ProjectFeature::PRIVATE)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_selector '.project-show-wiki'
end
@@ -74,7 +74,7 @@ describe 'Guest navigation menu' do
it 'shows the issues when enabled' do
project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_selector '.issues-list'
end
diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb
index b5c64777934..62d244ff259 100644
--- a/spec/features/projects/import_export/export_file_spec.rb
+++ b/spec/features/projects/import_export/export_file_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
# It looks up for any sensitive word inside the JSON, so if a sensitive word is found
# we''l have to either include it adding the model that includes it to the +safe_list+
# or make sure the attribute is blacklisted in the +import_export.yml+ configuration
-feature 'Import/Export - project export integration test', feature: true, js: true do
+feature 'Import/Export - project export integration test', js: true do
include Select2Helper
include ExportFileHelper
@@ -33,17 +33,17 @@ feature 'Import/Export - project export integration test', feature: true, js: tr
context 'admin user' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'exports a project successfully' do
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
expect(page).to have_content('Export project')
click_link 'Export project'
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
expect(page).to have_content('Download export')
diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb
index a111aa87c52..f924725870b 100644
--- a/spec/features/projects/import_export/import_file_spec.rb
+++ b/spec/features/projects/import_export/import_file_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Import/Export - project import integration test', feature: true, js: true do
+feature 'Import/Export - project import integration test', js: true do
include Select2Helper
let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') }
@@ -46,14 +46,13 @@ feature 'Import/Export - project import integration test', feature: true, js: tr
end
scenario 'invalid project' do
- project = create(:project, namespace: namespace)
+ project = create(:empty_project, namespace: namespace)
visit new_project_path
select2(namespace.id, from: '#project_namespace_id')
fill_in :project_path, with: project.name, visible: true
click_link 'GitLab export'
-
attach_file('file', file)
click_on 'Import project'
@@ -63,7 +62,7 @@ feature 'Import/Export - project import integration test', feature: true, js: tr
end
scenario 'project with no name' do
- create(:project, namespace: namespace)
+ create(:empty_project, namespace: namespace)
visit new_project_path
@@ -98,6 +97,6 @@ feature 'Import/Export - project import integration test', feature: true, js: tr
end
def project_hook_exists?(project)
- Gitlab::Git::Hook.new('post-receive', project.repository.path).exists?
+ Gitlab::Git::Hook.new('post-receive', project).exists?
end
end
diff --git a/spec/features/projects/import_export/namespace_export_file_spec.rb b/spec/features/projects/import_export/namespace_export_file_spec.rb
index b0a68f0d61f..3917e72c39e 100644
--- a/spec/features/projects/import_export/namespace_export_file_spec.rb
+++ b/spec/features/projects/import_export/namespace_export_file_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Import/Export - Namespace export file cleanup', feature: true, js: true do
+feature 'Import/Export - Namespace export file cleanup', js: true do
let(:export_path) { "#{Dir.tmpdir}/import_file_spec" }
let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys }
@@ -16,7 +16,7 @@ feature 'Import/Export - Namespace export file cleanup', feature: true, js: true
context 'admin user' do
before do
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
end
context 'moving the namespace' do
@@ -48,13 +48,13 @@ feature 'Import/Export - Namespace export file cleanup', feature: true, js: true
end
def setup_export_project
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
expect(page).to have_content('Export project')
click_link 'Export project'
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
expect(page).to have_content('Download export')
end
diff --git a/spec/features/projects/issuable_counts_caching_spec.rb b/spec/features/projects/issuable_counts_caching_spec.rb
new file mode 100644
index 00000000000..703d1cbd327
--- /dev/null
+++ b/spec/features/projects/issuable_counts_caching_spec.rb
@@ -0,0 +1,132 @@
+require 'spec_helper'
+
+describe 'Issuable counts caching', :use_clean_rails_memory_store_caching do
+ let!(:member) { create(:user) }
+ let!(:member_2) { create(:user) }
+ let!(:non_member) { create(:user) }
+ let!(:project) { create(:empty_project, :public) }
+ let!(:open_issue) { create(:issue, project: project) }
+ let!(:confidential_issue) { create(:issue, :confidential, project: project, author: non_member) }
+ let!(:closed_issue) { create(:issue, :closed, project: project) }
+
+ before do
+ project.add_developer(member)
+ project.add_developer(member_2)
+ end
+
+ it 'caches issuable counts correctly for non-members' do
+ # We can't use expect_any_instance_of because that uses a single instance.
+ counts = 0
+
+ allow_any_instance_of(IssuesFinder).to receive(:count_by_state).and_wrap_original do |m, *args|
+ counts += 1
+
+ m.call(*args)
+ end
+
+ aggregate_failures 'only counts once on first load with no params, and caches for later loads' do
+ expect { visit project_issues_path(project) }
+ .to change { counts }.by(1)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+ end
+
+ aggregate_failures 'uses counts from cache on load from non-member' do
+ sign_in(non_member)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_out(non_member)
+ end
+
+ aggregate_failures 'does not use the same cache for a member' do
+ sign_in(member)
+
+ expect { visit project_issues_path(project) }
+ .to change { counts }.by(1)
+
+ sign_out(member)
+ end
+
+ aggregate_failures 'uses the same cache for all members' do
+ sign_in(member_2)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_out(member_2)
+ end
+
+ aggregate_failures 'shares caches when params are passed' do
+ expect { visit project_issues_path(project, author_username: non_member.username) }
+ .to change { counts }.by(1)
+
+ sign_in(member)
+
+ expect { visit project_issues_path(project, author_username: non_member.username) }
+ .to change { counts }.by(1)
+
+ sign_in(non_member)
+
+ expect { visit project_issues_path(project, author_username: non_member.username) }
+ .not_to change { counts }
+
+ sign_in(member_2)
+
+ expect { visit project_issues_path(project, author_username: non_member.username) }
+ .not_to change { counts }
+
+ sign_out(member_2)
+ end
+
+ aggregate_failures 'resets caches on issue close' do
+ Issues::CloseService.new(project, member).execute(open_issue)
+
+ expect { visit project_issues_path(project) }
+ .to change { counts }.by(1)
+
+ sign_in(member)
+
+ expect { visit project_issues_path(project) }
+ .to change { counts }.by(1)
+
+ sign_in(non_member)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_in(member_2)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_out(member_2)
+ end
+
+ aggregate_failures 'does not reset caches on issue update' do
+ Issues::UpdateService.new(project, member, title: 'new title').execute(open_issue)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_in(member)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_in(non_member)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_in(member_2)
+
+ expect { visit project_issues_path(project) }
+ .not_to change { counts }
+
+ sign_out(member_2)
+ end
+ end
+end
diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb
index 26a09985312..d2789d0aa52 100644
--- a/spec/features/projects/issuable_templates_spec.rb
+++ b/spec/features/projects/issuable_templates_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'issuable templates', feature: true, js: true do
+feature 'issuable templates', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
before do
project.team << [user, :master]
- gitlab_sign_in user
+ sign_in user
end
context 'user creates an issue using templates' do
@@ -28,7 +28,7 @@ feature 'issuable templates', feature: true, js: true do
longtemplate_content,
message: 'added issue template',
branch_name: 'master')
- visit edit_namespace_project_issue_path project.namespace, project, issue
+ visit edit_project_issue_path project, issue
fill_in :'issue[title]', with: 'test issue title'
end
@@ -81,7 +81,7 @@ feature 'issuable templates', feature: true, js: true do
template_content,
message: 'added issue template',
branch_name: 'master')
- visit edit_namespace_project_issue_path project.namespace, project, issue
+ visit edit_project_issue_path project, issue
fill_in :'issue[title]', with: 'test issue title'
fill_in :'issue[description]', with: prior_description
end
@@ -105,7 +105,7 @@ feature 'issuable templates', feature: true, js: true do
template_content,
message: 'added merge request template',
branch_name: 'master')
- visit edit_namespace_project_merge_request_path project.namespace, project, merge_request
+ visit edit_project_merge_request_path project, merge_request
fill_in :'merge_request[title]', with: 'test merge request title'
end
@@ -120,22 +120,25 @@ feature 'issuable templates', feature: true, js: true do
context 'user creates a merge request from a forked project using templates' do
let(:template_content) { 'this is a test "feature-proposal" template' }
let(:fork_user) { create(:user) }
- let(:fork_project) { create(:project, :public) }
+ let(:fork_project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, :with_diffs, source_project: fork_project, target_project: project) }
background do
- gitlab_sign_out
+ sign_out(:user)
+
project.team << [fork_user, :developer]
fork_project.team << [fork_user, :master]
create(:forked_project_link, forked_to_project: fork_project, forked_from_project: project)
- gitlab_sign_in fork_user
+
+ sign_in(fork_user)
+
project.repository.create_file(
fork_user,
'.gitlab/merge_request_templates/feature-proposal.md',
template_content,
message: 'added merge request template',
branch_name: 'master')
- visit edit_namespace_project_merge_request_path project.namespace, project, merge_request
+ visit edit_project_merge_request_path project, merge_request
fill_in :'merge_request[title]', with: 'test merge request title'
end
diff --git a/spec/features/projects/issues/list_spec.rb b/spec/features/projects/issues/list_spec.rb
index b2db07a75ef..c2ca62508a4 100644
--- a/spec/features/projects/issues/list_spec.rb
+++ b/spec/features/projects/issues/list_spec.rb
@@ -7,13 +7,13 @@ feature 'Issues List' do
background do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'user does not see create new list button' do
create(:issue, project: project)
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
expect(page).not_to have_selector('.js-new-board-list')
end
diff --git a/spec/features/projects/issues/rss_spec.rb b/spec/features/projects/issues/rss_spec.rb
index 38733d39932..d274a1760a4 100644
--- a/spec/features/projects/issues/rss_spec.rb
+++ b/spec/features/projects/issues/rss_spec.rb
@@ -2,17 +2,18 @@ require 'spec_helper'
feature 'Project Issues RSS' do
let(:project) { create(:empty_project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:path) { namespace_project_issues_path(project.namespace, project) }
+ let(:path) { project_issues_path(project) }
before do
create(:issue, project: project)
end
context 'when signed in' do
+ let(:user) { create(:user) }
+
before do
- user = create(:user)
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 8457d8a8785..3fa32e2d10b 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -1,11 +1,10 @@
require 'spec_helper'
require 'tempfile'
-feature 'Jobs', :feature do
+feature 'Jobs' do
let(:user) { create(:user) }
let(:user_access_level) { :developer }
- let(:project) { create(:project) }
- let(:namespace) { project.namespace }
+ let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:job) { create(:ci_build, :trace, pipeline: pipeline) }
@@ -17,7 +16,7 @@ feature 'Jobs', :feature do
before do
project.team << [user, user_access_level]
- gitlab_sign_in(user)
+ sign_in(user)
end
describe "GET /:project/jobs" do
@@ -25,7 +24,7 @@ feature 'Jobs', :feature do
context "Pending scope" do
before do
- visit namespace_project_jobs_path(project.namespace, project, scope: :pending)
+ visit project_jobs_path(project, scope: :pending)
end
it "shows Pending tab jobs" do
@@ -40,7 +39,7 @@ feature 'Jobs', :feature do
context "Running scope" do
before do
job.run!
- visit namespace_project_jobs_path(project.namespace, project, scope: :running)
+ visit project_jobs_path(project, scope: :running)
end
it "shows Running tab jobs" do
@@ -55,7 +54,7 @@ feature 'Jobs', :feature do
context "Finished scope" do
before do
job.run!
- visit namespace_project_jobs_path(project.namespace, project, scope: :finished)
+ visit project_jobs_path(project, scope: :finished)
end
it "shows Finished tab jobs" do
@@ -68,7 +67,7 @@ feature 'Jobs', :feature do
context "All jobs" do
before do
project.builds.running_or_pending.each(&:success)
- visit namespace_project_jobs_path(project.namespace, project)
+ visit project_jobs_path(project)
end
it "shows All tab jobs" do
@@ -82,7 +81,7 @@ feature 'Jobs', :feature do
context "when visiting old URL" do
let(:jobs_url) do
- namespace_project_jobs_path(project.namespace, project)
+ project_jobs_path(project)
end
before do
@@ -98,7 +97,7 @@ feature 'Jobs', :feature do
describe "POST /:project/jobs/:id/cancel_all" do
before do
job.run!
- visit namespace_project_jobs_path(project.namespace, project)
+ visit project_jobs_path(project)
click_link "Cancel running"
end
@@ -117,7 +116,7 @@ feature 'Jobs', :feature do
let(:job) { create(:ci_build, :success, pipeline: pipeline) }
before do
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
it 'shows status name', :js do
@@ -140,7 +139,7 @@ feature 'Jobs', :feature do
let(:job) { create(:ci_build, :success, pipeline: pipeline) }
before do
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
it 'shows retry button' do
@@ -157,7 +156,7 @@ feature 'Jobs', :feature do
let(:job) { create(:ci_build, :failed, pipeline: pipeline) }
before do
- visit namespace_project_job_path(namespace, project, job)
+ visit project_job_path(project, job)
end
it 'shows New issue button' do
@@ -166,10 +165,10 @@ feature 'Jobs', :feature do
it 'links to issues/new with the title and description filled in' do
button_title = "Build Failed ##{job.id}"
- job_path = namespace_project_job_path(namespace, project, job)
+ job_path = project_job_path(project, job)
options = { issue: { title: button_title, description: job_path } }
- href = new_namespace_project_issue_path(namespace, project, options)
+ href = new_project_issue_path(project, options)
page.within('.header-action-buttons') do
expect(find('.js-new-issue')['href']).to include(href)
@@ -180,7 +179,7 @@ feature 'Jobs', :feature do
context "Job from other project" do
before do
- visit namespace_project_job_path(project.namespace, project, job2)
+ visit project_job_path(project, job2)
end
it { expect(page.status_code).to eq(404) }
@@ -189,7 +188,7 @@ feature 'Jobs', :feature do
context "Download artifacts" do
before do
job.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
it 'has button to download artifacts' do
@@ -202,7 +201,7 @@ feature 'Jobs', :feature do
job.update_attributes(artifacts_file: artifacts_file,
artifacts_expire_at: expire_at)
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
context 'no expire date defined' do
@@ -248,7 +247,7 @@ feature 'Jobs', :feature do
context "when visiting old URL" do
let(:job_url) do
- namespace_project_job_path(project.namespace, project, job)
+ project_job_path(project, job)
end
before do
@@ -264,7 +263,7 @@ feature 'Jobs', :feature do
before do
job.run!
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
it do
@@ -276,7 +275,7 @@ feature 'Jobs', :feature do
before do
job.run!
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
context 'when job has an initial trace' do
@@ -300,7 +299,7 @@ feature 'Jobs', :feature do
end
before do
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
end
it 'shows variable key and value after click', js: true do
@@ -325,7 +324,7 @@ feature 'Jobs', :feature do
let(:job) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) }
it 'shows a link for the job' do
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
expect(page).to have_link environment.name
end
@@ -335,7 +334,7 @@ feature 'Jobs', :feature do
let(:job) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) }
it 'shows a link for the job' do
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
expect(page).to have_link environment.name
end
@@ -346,7 +345,7 @@ feature 'Jobs', :feature do
let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
it 'shows a link to latest deployment' do
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
expect(page).to have_link('latest deployment')
end
@@ -358,7 +357,7 @@ feature 'Jobs', :feature do
context "Job from project" do
before do
job.run!
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
find('.js-cancel-job').click()
end
@@ -373,7 +372,7 @@ feature 'Jobs', :feature do
context "Job from project", :js do
before do
job.run!
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
find('.js-cancel-job').click()
find('.js-retry-button').click
end
@@ -392,9 +391,9 @@ feature 'Jobs', :feature do
job.cancel!
project.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- gitlab_sign_out_direct
- gitlab_sign_in(create(:user))
- visit namespace_project_job_path(project.namespace, project, job)
+ sign_out(:user)
+ sign_in(create(:user))
+ visit project_job_path(project, job)
end
it 'does not show the Retry button' do
@@ -408,14 +407,14 @@ feature 'Jobs', :feature do
describe "GET /:project/jobs/:id/download" do
before do
job.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
click_link 'Download'
end
context "Build from other project" do
before do
job2.update_attributes(artifacts_file: artifacts_file)
- visit download_namespace_project_job_artifacts_path(project.namespace, project, job2)
+ visit download_project_job_artifacts_path(project, job2)
end
it { expect(page.status_code).to eq(404) }
@@ -428,7 +427,7 @@ feature 'Jobs', :feature do
before do
Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' }
job.run!
- visit namespace_project_job_path(project.namespace, project, job)
+ visit project_job_path(project, job)
find('.js-raw-link-controller').click()
end
@@ -443,7 +442,7 @@ feature 'Jobs', :feature do
before do
Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' }
job2.run!
- visit raw_namespace_project_job_path(project.namespace, project, job2)
+ visit raw_project_job_path(project, job2)
end
it 'sends the right headers' do
@@ -467,7 +466,7 @@ feature 'Jobs', :feature do
.to receive(:paths)
.and_return([existing_file])
- visit namespace_project_job_path(namespace, project, job)
+ visit project_job_path(project, job)
find('.js-raw-link-controller').click
end
@@ -485,7 +484,7 @@ feature 'Jobs', :feature do
.to receive(:paths)
.and_return([])
- visit namespace_project_job_path(namespace, project, job)
+ visit project_job_path(project, job)
end
it 'sends the right headers' do
@@ -496,7 +495,7 @@ feature 'Jobs', :feature do
context "when visiting old URL" do
let(:raw_job_url) do
- raw_namespace_project_job_path(project.namespace, project, job)
+ raw_project_job_path(project, job)
end
before do
@@ -512,7 +511,7 @@ feature 'Jobs', :feature do
describe "GET /:project/jobs/:id/trace.json" do
context "Job from project" do
before do
- visit trace_namespace_project_job_path(project.namespace, project, job, format: :json)
+ visit trace_project_job_path(project, job, format: :json)
end
it { expect(page.status_code).to eq(200) }
@@ -520,7 +519,7 @@ feature 'Jobs', :feature do
context "Job from other project" do
before do
- visit trace_namespace_project_job_path(project.namespace, project, job2, format: :json)
+ visit trace_project_job_path(project, job2, format: :json)
end
it { expect(page.status_code).to eq(404) }
@@ -530,7 +529,7 @@ feature 'Jobs', :feature do
describe "GET /:project/jobs/:id/status" do
context "Job from project" do
before do
- visit status_namespace_project_job_path(project.namespace, project, job)
+ visit status_project_job_path(project, job)
end
it { expect(page.status_code).to eq(200) }
@@ -538,7 +537,7 @@ feature 'Jobs', :feature do
context "Job from other project" do
before do
- visit status_namespace_project_job_path(project.namespace, project, job2)
+ visit status_project_job_path(project, job2)
end
it { expect(page.status_code).to eq(404) }
diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
index 2c47758f30e..2b0aead440c 100644
--- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
+++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Issue prioritization', feature: true do
+feature 'Issue prioritization' do
let(:user) { create(:user) }
- let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+ let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
# Labels
let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
@@ -28,8 +28,8 @@ feature 'Issue prioritization', feature: true do
issue_2.labels << label_4
issue_1.labels << label_5
- gitlab_sign_in user
- visit namespace_project_issues_path(project.namespace, project, sort: 'label_priority')
+ sign_in user
+ visit project_issues_path(project, sort: 'label_priority')
# Ensure we are indicating that issues are sorted by priority
expect(page).to have_selector('.dropdown-toggle', text: 'Label priority')
@@ -67,8 +67,8 @@ feature 'Issue prioritization', feature: true do
issue_4.labels << label_4 # 7
issue_6.labels << label_5 # 8 - No priority
- gitlab_sign_in user
- visit namespace_project_issues_path(project.namespace, project, sort: 'label_priority')
+ sign_in user
+ visit project_issues_path(project, sort: 'label_priority')
expect(page).to have_selector('.dropdown-toggle', text: 'Label priority')
diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb
index 584dc294f05..3115a643d5d 100644
--- a/spec/features/projects/labels/subscription_spec.rb
+++ b/spec/features/projects/labels/subscription_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Labels subscription', feature: true do
+feature 'Labels subscription' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:empty_project, :public, namespace: group) }
@@ -10,11 +10,11 @@ feature 'Labels subscription', feature: true do
context 'when signed in' do
before do
project.team << [user, :developer]
- gitlab_sign_in user
+ sign_in user
end
scenario 'users can subscribe/unsubscribe to labels', js: true do
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content('bug')
expect(page).to have_content('feature')
@@ -55,7 +55,7 @@ feature 'Labels subscription', feature: true do
context 'when not signed in' do
it 'users can not subscribe/unsubscribe to labels' do
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content 'bug'
expect(page).to have_content 'feature'
diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb
index 589bfb9fbc9..223f94ff9f9 100644
--- a/spec/features/projects/labels/update_prioritization_spec.rb
+++ b/spec/features/projects/labels/update_prioritization_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Prioritize labels', feature: true do
+feature 'Prioritize labels' do
include DragTo
let(:user) { create(:user) }
@@ -14,11 +14,11 @@ feature 'Prioritize labels', feature: true do
before do
project.team << [user, :developer]
- gitlab_sign_in user
+ sign_in user
end
scenario 'user can prioritize a group label', js: true do
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content('Star labels to start sorting by priority')
@@ -37,7 +37,7 @@ feature 'Prioritize labels', feature: true do
scenario 'user can unprioritize a group label', js: true do
create(:label_priority, project: project, label: feature, priority: 1)
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
page.within('.prioritized-labels') do
expect(page).to have_content('feature')
@@ -53,7 +53,7 @@ feature 'Prioritize labels', feature: true do
end
scenario 'user can prioritize a project label', js: true do
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content('Star labels to start sorting by priority')
@@ -72,7 +72,7 @@ feature 'Prioritize labels', feature: true do
scenario 'user can unprioritize a project label', js: true do
create(:label_priority, project: project, label: bug, priority: 1)
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
page.within('.prioritized-labels') do
expect(page).to have_content('bug')
@@ -92,7 +92,7 @@ feature 'Prioritize labels', feature: true do
create(:label_priority, project: project, label: bug, priority: 1)
create(:label_priority, project: project, label: feature, priority: 2)
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content 'bug'
expect(page).to have_content 'feature'
@@ -114,31 +114,39 @@ feature 'Prioritize labels', feature: true do
expect(page.all('li').last).to have_content('bug')
end
end
+
+ it 'shows a help message about prioritized labels' do
+ visit project_labels_path(project)
+
+ expect(page).to have_content 'Star a label'
+ end
end
context 'as a guest' do
it 'does not prioritize labels' do
guest = create(:user)
- gitlab_sign_in guest
+ sign_in guest
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content 'bug'
expect(page).to have_content 'wontfix'
expect(page).to have_content 'feature'
expect(page).not_to have_css('.prioritized-labels')
+ expect(page).not_to have_content 'Star a label'
end
end
context 'as a non signed in user' do
it 'does not prioritize labels' do
- visit namespace_project_labels_path(project.namespace, project)
+ visit project_labels_path(project)
expect(page).to have_content 'bug'
expect(page).to have_content 'wontfix'
expect(page).to have_content 'feature'
expect(page).not_to have_css('.prioritized-labels')
+ expect(page).not_to have_content 'Star a label'
end
end
end
diff --git a/spec/features/projects/main/download_buttons_spec.rb b/spec/features/projects/main/download_buttons_spec.rb
index 514453db472..3f2579bb01a 100644
--- a/spec/features/projects/main/download_buttons_spec.rb
+++ b/spec/features/projects/main/download_buttons_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-feature 'Download buttons in project main page', feature: true do
+feature 'Download buttons in project main page' do
given(:user) { create(:user) }
given(:role) { :developer }
given(:status) { 'success' }
- given(:project) { create(:project) }
+ given(:project) { create(:project, :repository) }
given(:pipeline) do
create(:ci_pipeline,
@@ -22,20 +22,18 @@ feature 'Download buttons in project main page', feature: true do
end
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
end
describe 'when checking project main page' do
context 'with artifacts' do
before do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
scenario 'shows download artifacts button' do
- href = latest_succeeded_namespace_project_artifacts_path(
- project.namespace, project, "#{project.default_branch}/download",
- job: 'build')
+ href = latest_succeeded_project_artifacts_path(project, "#{project.default_branch}/download", job: 'build')
expect(page).to have_link "Download '#{build.name}'", href: href
end
diff --git a/spec/features/projects/main/rss_spec.rb b/spec/features/projects/main/rss_spec.rb
index fee8cfe2c33..7914180b951 100644
--- a/spec/features/projects/main/rss_spec.rb
+++ b/spec/features/projects/main/rss_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
feature 'Project RSS' do
+ let(:user) { create(:user) }
let(:project) { create(:project, :repository, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:path) { namespace_project_path(project.namespace, project) }
+ let(:path) { project_path(project) }
context 'when signed in' do
before do
- user = create(:user)
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
index d82cf53c690..a26e7becdb9 100644
--- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb
+++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Projects > Members > Anonymous user sees members', feature: true do
+feature 'Projects > Members > Anonymous user sees members' do
let(:user) { create(:user) }
let(:group) { create(:group, :public) }
let(:project) { create(:empty_project, :public) }
@@ -11,10 +11,10 @@ feature 'Projects > Members > Anonymous user sees members', feature: true do
end
scenario "anonymous user visits the project's members page and sees the list of members" do
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_project_members_path(project)
expect(current_path).to eq(
- namespace_project_settings_members_path(project.namespace, project))
+ project_project_members_path(project))
expect(page).to have_content(user.name)
end
end
diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb
index 00d2a27597b..acda5808313 100644
--- a/spec/features/projects/members/group_links_spec.rb
+++ b/spec/features/projects/members/group_links_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Projects > Members > Anonymous user sees members', feature: true, js: true do
+feature 'Projects > Members > Anonymous user sees members', js: true do
let(:user) { create(:user) }
let(:group) { create(:group, :public) }
let(:project) { create(:empty_project, :public) }
@@ -9,8 +9,8 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t
project.team << [user, :master]
@group_link = create(:project_group_link, project: project, group: group)
- gitlab_sign_in(user)
- visit namespace_project_settings_members_path(project.namespace, project)
+ sign_in(user)
+ visit project_settings_members_path(project)
end
it 'updates group access level' do
@@ -22,7 +22,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t
wait_for_requests
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
expect(first('.group_member')).to have_content('Guest')
end
diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
index 7e71dbc24c0..1fb5e000239 100644
--- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
+++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-feature 'Projects > Members > Group member cannot leave group project', feature: true do
+feature 'Projects > Members > Group member cannot leave group project' do
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:empty_project, namespace: group) }
background do
group.add_developer(user)
- gitlab_sign_in(user)
- visit namespace_project_path(project.namespace, project)
+ sign_in(user)
+ visit project_path(project)
end
scenario 'user does not see a "Leave project" link' do
diff --git a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb
index 60a5cd9ec63..8e3520f9f15 100644
--- a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb
+++ b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-feature 'Projects > Members > Group member cannot request access to his group project', feature: true do
+feature 'Projects > Members > Group member cannot request access to his group project' do
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:empty_project, namespace: group) }
scenario 'owner does not see the request access button' do
group.add_owner(user)
@@ -41,7 +41,7 @@ feature 'Projects > Members > Group member cannot request access to his group pr
end
def login_and_visit_project_page(user)
- gitlab_sign_in(user)
- visit namespace_project_path(project.namespace, project)
+ sign_in(user)
+ visit project_path(project)
end
end
diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb
index 76fe6a00dab..154f9f4a26c 100644
--- a/spec/features/projects/members/group_members_spec.rb
+++ b/spec/features/projects/members/group_members_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Projects members', feature: true do
+feature 'Projects members' do
let(:user) { create(:user) }
let(:developer) { create(:user) }
let(:group) { create(:group, :public, :access_requestable) }
@@ -13,13 +13,13 @@ feature 'Projects members', feature: true do
background do
project.team << [developer, :developer]
group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'with a group invitee' do
before do
group_invitee
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
end
scenario 'does not appear in the project members page' do
@@ -33,7 +33,7 @@ feature 'Projects members', feature: true do
before do
group_invitee
project_invitee
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
end
scenario 'shows the project invitee, the project developer, and the group owner' do
@@ -54,7 +54,7 @@ feature 'Projects members', feature: true do
context 'with a group requester' do
before do
group.request_access(group_requester)
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
end
scenario 'does not appear in the project members page' do
@@ -68,7 +68,7 @@ feature 'Projects members', feature: true do
before do
group.request_access(group_requester)
project.request_access(project_requester)
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
end
scenario 'shows the project requester, the project developer, and the group owner' do
diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
index 66da28b07fe..6865d721201 100644
--- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
+++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
@@ -1,17 +1,17 @@
require 'spec_helper'
-feature 'Projects > Members > Group requester cannot request access to project', feature: true, js: true do
+feature 'Projects > Members > Group requester cannot request access to project', js: true do
let(:user) { create(:user) }
let(:owner) { create(:user) }
let(:group) { create(:group, :public, :access_requestable) }
- let(:project) { create(:project, :public, :access_requestable, namespace: group) }
+ let(:project) { create(:empty_project, :public, :access_requestable, namespace: group) }
background do
group.add_owner(owner)
- gitlab_sign_in(user)
+ sign_in(user)
visit group_path(group)
perform_enqueued_jobs { click_link 'Request Access' }
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
scenario 'group requester does not see the request access / withdraw access request button' do
diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb
index 9fdd7df0ee5..f9c54d267b5 100644
--- a/spec/features/projects/members/list_spec.rb
+++ b/spec/features/projects/members/list_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-feature 'Project members list', feature: true do
+feature 'Project members list' do
include Select2Helper
let(:user1) { create(:user, name: 'John Doe') }
let(:user2) { create(:user, name: 'Mary Jane') }
let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
+ let(:project) { create(:empty_project, namespace: group) }
background do
- gitlab_sign_in(user1)
+ sign_in(user1)
group.add_owner(user1)
end
@@ -85,6 +85,6 @@ feature 'Project members list', feature: true do
end
def visit_members_page
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_settings_members_path(project)
end
end
diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
index 21b48b7fdd1..b4381ea373e 100644
--- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
@@ -1,22 +1,22 @@
require 'spec_helper'
-feature 'Projects > Members > Master adds member with expiration date', feature: true, js: true do
+feature 'Projects > Members > Master adds member with expiration date', js: true do
include Select2Helper
include ActiveSupport::Testing::TimeHelpers
let(:master) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let!(:new_member) { create(:user) }
background do
project.team << [master, :master]
- gitlab_sign_in(master)
+ sign_in(master)
end
scenario 'expiration date is displayed in the members list' do
travel_to Time.zone.parse('2016-08-06 08:00') do
date = 4.days.from_now
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
page.within '.users-project-form' do
select2(new_member.id, from: '#user_ids', multiple: true)
@@ -34,7 +34,7 @@ feature 'Projects > Members > Master adds member with expiration date', feature:
travel_to Time.zone.parse('2016-08-06 08:00') do
date = 3.days.from_now
project.team.add_users([new_member.id], :developer, expires_at: Date.today.to_s(:medium))
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
page.within "#project_member_#{new_member.project_members.first.id}" do
find('.js-access-expiration-date').set date.to_s(:medium)
diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb
index bd445e27243..0f96a7cc70d 100644
--- a/spec/features/projects/members/master_manages_access_requests_spec.rb
+++ b/spec/features/projects/members/master_manages_access_requests_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Projects > Members > Master manages access requests', feature: true do
+feature 'Projects > Members > Master manages access requests' do
let(:user) { create(:user) }
let(:master) { create(:user) }
let(:project) { create(:empty_project, :public, :access_requestable) }
@@ -8,17 +8,17 @@ feature 'Projects > Members > Master manages access requests', feature: true do
background do
project.request_access(user)
project.team << [master, :master]
- gitlab_sign_in(master)
+ sign_in(master)
end
scenario 'master can see access requests' do
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
expect_visible_access_request(project, user)
end
scenario 'master can grant access' do
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
expect_visible_access_request(project, user)
@@ -29,7 +29,7 @@ feature 'Projects > Members > Master manages access requests', feature: true do
end
scenario 'master can deny access' do
- visit namespace_project_project_members_path(project.namespace, project)
+ visit project_project_members_path(project)
expect_visible_access_request(project, user)
diff --git a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb
index 703f5dff6b5..7f39f5b2513 100644
--- a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb
+++ b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Projects > Members > Member cannot request access to his project', feature: true do
+feature 'Projects > Members > Member cannot request access to his project' do
let(:member) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
background do
project.team << [member, :developer]
- gitlab_sign_in(member)
- visit namespace_project_path(project.namespace, project)
+ sign_in(member)
+ visit project_path(project)
end
scenario 'member does not see the request access button' do
diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb
index 8e1788f7f2a..1bcf827d33c 100644
--- a/spec/features/projects/members/member_leaves_project_spec.rb
+++ b/spec/features/projects/members/member_leaves_project_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Projects > Members > Member leaves project', feature: true do
+feature 'Projects > Members > Member leaves project' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
background do
project.team << [user, :developer]
- gitlab_sign_in(user)
- visit namespace_project_path(project.namespace, project)
+ sign_in(user)
+ visit project_path(project)
end
scenario 'user leaves project' do
diff --git a/spec/features/projects/members/owner_cannot_leave_project_spec.rb b/spec/features/projects/members/owner_cannot_leave_project_spec.rb
index 70e4bb19c0f..8b6d0aafcf8 100644
--- a/spec/features/projects/members/owner_cannot_leave_project_spec.rb
+++ b/spec/features/projects/members/owner_cannot_leave_project_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Projects > Members > Owner cannot leave project', feature: true do
- let(:project) { create(:project) }
+feature 'Projects > Members > Owner cannot leave project' do
+ let(:project) { create(:empty_project) }
background do
- gitlab_sign_in(project.owner)
- visit namespace_project_path(project.namespace, project)
+ sign_in(project.owner)
+ visit project_path(project)
end
scenario 'user does not see a "Leave project" link' do
diff --git a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb
index 0cd7e3afeda..d838af6d976 100644
--- a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb
+++ b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Projects > Members > Owner cannot request access to his project', feature: true do
- let(:project) { create(:project) }
+feature 'Projects > Members > Owner cannot request access to his project' do
+ let(:project) { create(:empty_project) }
background do
- gitlab_sign_in(project.owner)
- visit namespace_project_path(project.namespace, project)
+ sign_in(project.owner)
+ visit project_path(project)
end
scenario 'owner does not see the request access button' do
diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb
index 66d98ef8b90..45c2647e6e2 100644
--- a/spec/features/projects/members/sorting_spec.rb
+++ b/spec/features/projects/members/sorting_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Projects > Members > Sorting', feature: true do
+feature 'Projects > Members > Sorting' do
let(:master) { create(:user, name: 'John Doe') }
let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) }
let(:project) { create(:empty_project, namespace: master.namespace, creator: master) }
@@ -8,7 +8,7 @@ feature 'Projects > Members > Sorting', feature: true do
background do
create(:project_member, :developer, user: developer, project: project, created_at: 3.days.ago)
- gitlab_sign_in(master)
+ sign_in(master)
end
scenario 'sorts alphabetically by default' do
@@ -67,7 +67,7 @@ feature 'Projects > Members > Sorting', feature: true do
expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Name, descending')
end
- scenario 'sorts by recent sign in', :redis do
+ scenario 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :recent_sign_in)
expect(first_member).to include(master.name)
@@ -75,7 +75,7 @@ feature 'Projects > Members > Sorting', feature: true do
expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in')
end
- scenario 'sorts by oldest sign in', :redis do
+ scenario 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
visit_members_list(sort: :oldest_sign_in)
expect(first_member).to include(developer.name)
@@ -84,7 +84,7 @@ feature 'Projects > Members > Sorting', feature: true do
end
def visit_members_list(sort:)
- visit namespace_project_project_members_path(project.namespace.to_param, project, sort: sort)
+ visit project_project_members_path(project, sort: sort)
end
def first_member
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index 081009f2325..24c9f708456 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
-feature 'Projects > Members > User requests access', feature: true do
+feature 'Projects > Members > User requests access' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public, :access_requestable, :repository) }
let(:master) { project.owner }
background do
- gitlab_sign_in(user)
- visit namespace_project_path(project.namespace, project)
+ sign_in(user)
+ visit project_path(project)
end
scenario 'request access feature is disabled' do
project.update_attributes(request_access_enabled: false)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).not_to have_content 'Request Access'
end
@@ -35,7 +35,7 @@ feature 'Projects > Members > User requests access', feature: true do
project.project_feature.update!(repository_access_level: ProjectFeature::PRIVATE,
builds_access_level: ProjectFeature::PRIVATE,
merge_requests_access_level: ProjectFeature::PRIVATE)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_content 'Request Access'
end
@@ -46,10 +46,11 @@ feature 'Projects > Members > User requests access', feature: true do
expect(project.requesters.exists?(user_id: user)).to be_truthy
- open_project_settings_menu
- click_link 'Members'
+ page.within('.layout-nav .nav-links') do
+ click_link('Members')
+ end
- visit namespace_project_settings_members_path(project.namespace, project)
+ visit project_project_members_path(project)
page.within('.content') do
expect(page).not_to have_content(user.name)
end
diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb
index 6de8855016d..85d518c0cc3 100644
--- a/spec/features/projects/merge_request_button_spec.rb
+++ b/spec/features/projects/merge_request_button_spec.rb
@@ -1,36 +1,33 @@
require 'spec_helper'
-feature 'Merge Request button', feature: true do
+feature 'Merge Request button' do
shared_examples 'Merge request button only shown when allowed' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
- let(:forked_project) { create(:project, :public, forked_from_project: project) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:forked_project) { create(:project, :public, :repository, forked_from_project: project) }
context 'not logged in' do
it 'does not show Create merge request button' do
visit url
- within("#content-body") do
- expect(page).not_to have_link(label)
- end
+ expect(page).not_to have_link(label)
end
end
context 'logged in as developer' do
before do
- gitlab_sign_in(user)
- project.team << [user, :developer]
+ sign_in(user)
+ project.add_developer(user)
end
it 'shows Create merge request button' do
- href = new_namespace_project_merge_request_path(project.namespace,
- project,
- merge_request: { source_branch: 'feature',
- target_branch: 'master' })
+ href = project_new_merge_request_path(project,
+ merge_request: { source_branch: 'feature',
+ target_branch: 'master' })
visit url
- within("#content-body") do
+ within('#content-body') do
expect(page).to have_link(label, href: href)
end
end
@@ -43,7 +40,7 @@ feature 'Merge Request button', feature: true do
it 'does not show Create merge request button' do
visit url
- within("#content-body") do
+ within('#content-body') do
expect(page).not_to have_link(label)
end
end
@@ -52,13 +49,13 @@ feature 'Merge Request button', feature: true do
context 'logged in as non-member' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
it 'does not show Create merge request button' do
visit url
- within("#content-body") do
+ within('#content-body') do
expect(page).not_to have_link(label)
end
end
@@ -67,10 +64,9 @@ feature 'Merge Request button', feature: true do
let(:user) { forked_project.owner }
it 'shows Create merge request button' do
- href = new_namespace_project_merge_request_path(forked_project.namespace,
- forked_project,
- merge_request: { source_branch: 'feature',
- target_branch: 'master' })
+ href = project_new_merge_request_path(forked_project,
+ merge_request: { source_branch: 'feature',
+ target_branch: 'master' })
visit fork_url
@@ -85,24 +81,24 @@ feature 'Merge Request button', feature: true do
context 'on branches page' do
it_behaves_like 'Merge request button only shown when allowed' do
let(:label) { 'Merge request' }
- let(:url) { namespace_project_branches_path(project.namespace, project, search: 'feature') }
- let(:fork_url) { namespace_project_branches_path(forked_project.namespace, forked_project, search: 'feature') }
+ let(:url) { project_branches_path(project, search: 'feature') }
+ let(:fork_url) { project_branches_path(forked_project, search: 'feature') }
end
end
context 'on compare page' do
it_behaves_like 'Merge request button only shown when allowed' do
let(:label) { 'Create merge request' }
- let(:url) { namespace_project_compare_path(project.namespace, project, from: 'master', to: 'feature') }
- let(:fork_url) { namespace_project_compare_path(forked_project.namespace, forked_project, from: 'master', to: 'feature') }
+ let(:url) { project_compare_path(project, from: 'master', to: 'feature') }
+ let(:fork_url) { project_compare_path(forked_project, from: 'master', to: 'feature') }
end
end
context 'on commits page' do
it_behaves_like 'Merge request button only shown when allowed' do
let(:label) { 'Create merge request' }
- let(:url) { namespace_project_commits_path(project.namespace, project, 'feature') }
- let(:fork_url) { namespace_project_commits_path(forked_project.namespace, forked_project, 'feature') }
+ let(:url) { project_commits_path(project, 'feature') }
+ let(:fork_url) { project_commits_path(forked_project, 'feature') }
end
end
end
diff --git a/spec/features/projects/merge_requests/list_spec.rb b/spec/features/projects/merge_requests/list_spec.rb
index f2a2fd0311f..a879efef4b5 100644
--- a/spec/features/projects/merge_requests/list_spec.rb
+++ b/spec/features/projects/merge_requests/list_spec.rb
@@ -2,39 +2,39 @@ require 'spec_helper'
feature 'Merge Requests List' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
background do
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'user does not see create new list button' do
create(:merge_request, source_project: project)
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
expect(page).not_to have_selector('.js-new-board-list')
end
it 'should show an empty state' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
expect(page).to have_selector('.empty-state')
end
it 'empty state should have a create merge request button' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
- expect(page).to have_link 'New merge request', href: new_namespace_project_merge_request_path(project.namespace, project)
+ expect(page).to have_link 'New merge request', href: project_new_merge_request_path(project)
end
context 'if there are merge requests' do
before do
create(:merge_request, assignee: user, source_project: project)
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
end
it 'should not show an empty state' do
diff --git a/spec/features/projects/milestones/milestone_spec.rb b/spec/features/projects/milestones/milestone_spec.rb
index a02e4118784..b1c38ecc9ab 100644
--- a/spec/features/projects/milestones/milestone_spec.rb
+++ b/spec/features/projects/milestones/milestone_spec.rb
@@ -1,17 +1,17 @@
require 'spec_helper'
-feature 'Project milestone', :feature do
+feature 'Project milestone' do
let(:user) { create(:user) }
let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
let(:milestone) { create(:milestone, project: project) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when project has enabled issues' do
before do
- visit namespace_project_milestone_path(project.namespace, project, milestone)
+ visit project_milestone_path(project, milestone)
end
it 'shows issues tab' do
@@ -38,7 +38,7 @@ feature 'Project milestone', :feature do
context 'when project has disabled issues' do
before do
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
- visit namespace_project_milestone_path(project.namespace, project, milestone)
+ visit project_milestone_path(project, milestone)
end
it 'hides issues tab' do
@@ -68,7 +68,7 @@ feature 'Project milestone', :feature do
before do
create(:issue, project: project, milestone: milestone)
- visit namespace_project_milestone_path(project.namespace, project, milestone)
+ visit project_milestone_path(project, milestone)
end
describe 'the collapsed sidebar' do
diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb
index 2350089255d..4bd1929ac1e 100644
--- a/spec/features/projects/milestones/milestones_sorting_spec.rb
+++ b/spec/features/projects/milestones/milestones_sorting_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Milestones sorting', :feature, :js do
+feature 'Milestones sorting', :js do
include SortingHelper
let(:user) { create(:user) }
let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
@@ -15,11 +15,11 @@ feature 'Milestones sorting', :feature, :js do
due_date: 11.days.from_now,
created_at: 1.hour.ago,
title: "bbb", project: project)
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'visit project milestones and sort by due_date_asc' do
- visit namespace_project_milestones_path(project.namespace, project)
+ visit project_milestones_path(project)
expect(page).to have_button('Due soon')
diff --git a/spec/features/projects/milestones/new_spec.rb b/spec/features/projects/milestones/new_spec.rb
index 7403822c7fb..7cfcccda439 100644
--- a/spec/features/projects/milestones/new_spec.rb
+++ b/spec/features/projects/milestones/new_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Creating a new project milestone', :feature, :js do
+feature 'Creating a new project milestone', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) }
before do
login_as(user)
- visit new_namespace_project_milestone_path(project.namespace, project)
+ visit new_project_milestone_path(project)
end
it 'description has autocomplete' do
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index 37d9a97033b..22fb1223739 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -1,13 +1,27 @@
-require "spec_helper"
+require 'spec_helper'
-feature "New project", feature: true do
+feature 'New project' do
let(:user) { create(:admin) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
- context "Visibility level selector" do
+ it 'shows "New project" page' do
+ visit new_project_path
+
+ expect(page).to have_content('Project path')
+ expect(page).to have_content('Project name')
+
+ expect(page).to have_link('GitHub')
+ expect(page).to have_link('Bitbucket')
+ expect(page).to have_link('GitLab.com')
+ expect(page).to have_link('Google Code')
+ expect(page).to have_button('Repo by URL')
+ expect(page).to have_link('GitLab export')
+ end
+
+ context 'Visibility level selector' do
Gitlab::VisibilityLevel.options.each do |key, level|
it "sets selector to #{key}" do
stub_application_setting(default_project_visibility: level)
@@ -28,20 +42,20 @@ feature "New project", feature: true do
end
end
- context "Namespace selector" do
- context "with user namespace" do
+ context 'Namespace selector' do
+ context 'with user namespace' do
before do
visit new_project_path
end
- it "selects the user namespace" do
- namespace = find("#project_namespace_id")
+ it 'selects the user namespace' do
+ namespace = find('#project_namespace_id')
expect(namespace.text).to eq user.username
end
end
- context "with group namespace" do
+ context 'with group namespace' do
let(:group) { create(:group, :private, owner: user) }
before do
@@ -49,13 +63,13 @@ feature "New project", feature: true do
visit new_project_path(namespace_id: group.id)
end
- it "selects the group namespace" do
- namespace = find("#project_namespace_id option[selected]")
+ it 'selects the group namespace' do
+ namespace = find('#project_namespace_id option[selected]')
expect(namespace.text).to eq group.name
end
- context "on validation error" do
+ context 'on validation error' do
before do
fill_in('project_path', with: 'private-group-project')
choose('Internal')
@@ -64,15 +78,15 @@ feature "New project", feature: true do
expect(page).to have_css '.project-edit-errors .alert.alert-danger'
end
- it "selects the group namespace" do
- namespace = find("#project_namespace_id option[selected]")
+ it 'selects the group namespace' do
+ namespace = find('#project_namespace_id option[selected]')
expect(namespace.text).to eq group.name
end
end
end
- context "with subgroup namespace" do
+ context 'with subgroup namespace' do
let(:group) { create(:group, :private, owner: user) }
let(:subgroup) { create(:group, parent: group) }
@@ -81,8 +95,8 @@ feature "New project", feature: true do
visit new_project_path(namespace_id: subgroup.id)
end
- it "selects the group namespace" do
- namespace = find("#project_namespace_id option[selected]")
+ it 'selects the group namespace' do
+ namespace = find('#project_namespace_id option[selected]')
expect(namespace.text).to eq subgroup.full_path
end
@@ -94,10 +108,45 @@ feature "New project", feature: true do
visit new_project_path
end
- it 'does not autocomplete sensitive git repo URL' do
- autocomplete = find('#project_import_url')['autocomplete']
+ context 'from git repository url' do
+ before do
+ first('.import_git').click
+ end
+
+ it 'does not autocomplete sensitive git repo URL' do
+ autocomplete = find('#project_import_url')['autocomplete']
+
+ expect(autocomplete).to eq('off')
+ end
+
+ it 'shows import instructions' do
+ git_import_instructions = first('.js-toggle-content')
- expect(autocomplete).to eq('off')
+ expect(git_import_instructions).to be_visible
+ expect(git_import_instructions).to have_content 'Git repository URL'
+ end
+ end
+
+ context 'from GitHub' do
+ before do
+ first('.import_github').click
+ end
+
+ it 'shows import instructions' do
+ expect(page).to have_content('Import Projects from GitHub')
+ expect(current_path).to eq new_import_github_path
+ end
+ end
+
+ context 'from Google Code' do
+ before do
+ first('.import_google_code').click
+ end
+
+ it 'shows import instructions' do
+ expect(page).to have_content('Import projects from Google Code')
+ expect(current_path).to eq new_import_google_code_path
+ end
end
end
end
diff --git a/spec/features/projects/no_password_spec.rb b/spec/features/projects/no_password_spec.rb
new file mode 100644
index 00000000000..6aff079dd39
--- /dev/null
+++ b/spec/features/projects/no_password_spec.rb
@@ -0,0 +1,69 @@
+require 'spec_helper'
+
+feature 'No Password Alert' do
+ let(:project) { create(:project, :repository, namespace: user.namespace) }
+
+ context 'with internal auth enabled' do
+ before do
+ sign_in(user)
+ visit project_path(project)
+ end
+
+ context 'when user has a password' do
+ let(:user) { create(:user) }
+
+ it 'shows no alert' do
+ expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account"
+ end
+ end
+
+ context 'when user has password automatically set' do
+ let(:user) { create(:user, password_automatically_set: true) }
+
+ it 'shows a password alert' do
+ expect(page).to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account"
+ end
+ end
+ end
+
+ context 'with internal auth disabled' do
+ let(:user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'saml') }
+
+ before do
+ stub_application_setting(password_authentication_enabled?: false)
+ stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config])
+ end
+
+ context 'when user has no personal access tokens' do
+ it 'has a personal access token alert' do
+ gitlab_sign_in_via('saml', user, 'my-uid')
+ visit project_path(project)
+
+ expect(page).to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account"
+ end
+ end
+
+ context 'when user has a personal access token' do
+ it 'shows no alert' do
+ create(:personal_access_token, user: user)
+ gitlab_sign_in_via('saml', user, 'my-uid')
+ visit project_path(project)
+
+ expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account"
+ end
+ end
+ end
+
+ context 'when user is ldap user' do
+ let(:user) { create(:omniauth_user, password_automatically_set: true) }
+
+ before do
+ sign_in(user)
+ visit project_path(project)
+ end
+
+ it 'shows no alert' do
+ expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you"
+ end
+ end
+end
diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb
index e9a3cfb7f60..42f23ee5dec 100644
--- a/spec/features/projects/pages_spec.rb
+++ b/spec/features/projects/pages_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Pages', feature: true do
+feature 'Pages' do
given(:project) { create(:empty_project) }
given(:user) { create(:user) }
given(:role) { :master }
@@ -10,12 +10,12 @@ feature 'Pages', feature: true do
project.team << [user, role]
- gitlab_sign_in(user)
+ sign_in(user)
end
shared_examples 'no pages deployed' do
scenario 'does not see anything to destroy' do
- visit namespace_project_pages_path(project.namespace, project)
+ visit project_pages_path(project)
expect(page).not_to have_link('Remove pages')
expect(page).not_to have_text('Only the project owner can remove pages')
@@ -33,7 +33,7 @@ feature 'Pages', feature: true do
end
scenario 'sees "Remove pages" link' do
- visit namespace_project_pages_path(project.namespace, project)
+ visit project_pages_path(project)
expect(page).to have_link('Remove pages')
end
@@ -49,7 +49,7 @@ feature 'Pages', feature: true do
end
scenario 'sees "Only the project owner can remove pages" text' do
- visit namespace_project_pages_path(project.namespace, project)
+ visit project_pages_path(project)
expect(page).to have_text('Only the project owner can remove pages')
end
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index dfb973c37e5..605415d2af4 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -1,149 +1,268 @@
require 'spec_helper'
-feature 'Pipeline Schedules', :feature do
+feature 'Pipeline Schedules', :js do
include PipelineSchedulesHelper
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let!(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) }
let!(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
let(:scope) { nil }
let!(:user) { create(:user) }
- before do
- project.add_master(user)
+ context 'logged in as master' do
+ before do
+ project.add_master(user)
+ gitlab_sign_in(user)
+ end
- gitlab_sign_in(user)
- visit_page
- end
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+ end
- describe 'GET /projects/pipeline_schedules' do
- let(:visit_page) { visit_pipelines_schedules }
+ describe 'The view' do
+ it 'displays the required information description' do
+ page.within('.pipeline-schedule-table-row') do
+ expect(page).to have_content('pipeline schedule')
+ expect(find(".next-run-cell time")['data-original-title'])
+ .to include(pipeline_schedule.real_next_run.strftime('%b %-d, %Y'))
+ expect(page).to have_link('master')
+ expect(page).to have_link("##{pipeline.id}")
+ end
+ end
- it 'avoids N + 1 queries' do
- control_count = ActiveRecord::QueryRecorder.new { visit_pipelines_schedules }.count
+ it 'creates a new scheduled pipeline' do
+ click_link 'New schedule'
- create_list(:ci_pipeline_schedule, 2, project: project)
+ expect(page).to have_content('Schedule a new pipeline')
+ end
- expect { visit_pipelines_schedules }.not_to exceed_query_limit(control_count)
- end
+ it 'changes ownership of the pipeline' do
+ click_link 'Take ownership'
+ page.within('.pipeline-schedule-table-row') do
+ expect(page).not_to have_content('No owner')
+ expect(page).to have_link('John Doe')
+ end
+ end
- describe 'The view' do
- it 'displays the required information description' do
- page.within('.pipeline-schedule-table-row') do
- expect(page).to have_content('pipeline schedule')
- expect(page).to have_content(pipeline_schedule.real_next_run.strftime('%b %d, %Y'))
- expect(page).to have_link('master')
- expect(page).to have_link("##{pipeline.id}")
+ it 'edits the pipeline' do
+ page.within('.pipeline-schedule-table-row') do
+ click_link 'Edit'
+ end
+
+ expect(page).to have_content('Edit Pipeline Schedule')
end
- end
- it 'creates a new scheduled pipeline' do
- click_link 'New schedule'
+ it 'deletes the pipeline' do
+ click_link 'Delete'
- expect(page).to have_content('Schedule a new pipeline')
+ expect(page).not_to have_css(".pipeline-schedule-table-row")
+ end
end
- it 'changes ownership of the pipeline' do
- click_link 'Take ownership'
- page.within('.pipeline-schedule-table-row') do
- expect(page).not_to have_content('No owner')
- expect(page).to have_link('John Doe')
+ context 'when ref is nil' do
+ before do
+ pipeline_schedule.update_attribute(:ref, nil)
+ visit_pipelines_schedules
+ end
+
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ expect(first('.branch-name-cell').text).to eq('')
end
end
- it 'edits the pipeline' do
- page.within('.pipeline-schedule-table-row') do
- click_link 'Edit'
+ context 'when ref is empty' do
+ before do
+ pipeline_schedule.update_attribute(:ref, '')
+ visit_pipelines_schedules
end
- expect(page).to have_content('Edit Pipeline Schedule')
+ it 'shows a list of the pipeline schedules with empty ref column' do
+ expect(first('.branch-name-cell').text).to eq('')
+ end
end
+ end
- it 'deletes the pipeline' do
- click_link 'Delete'
+ describe 'POST /projects/pipeline_schedules/new' do
+ before do
+ visit_new_pipeline_schedule
+ end
- expect(page).not_to have_content('pipeline schedule')
+ it 'sets defaults for timezone and target branch' do
+ expect(page).to have_button('master')
+ expect(page).to have_button('UTC')
+ end
+
+ it 'it creates a new scheduled pipeline' do
+ fill_in_schedule_form
+ save_pipeline_schedule
+
+ expect(page).to have_content('my fancy description')
+ end
+
+ it 'it prevents an invalid form from being submitted' do
+ save_pipeline_schedule
+
+ expect(page).to have_content('This field is required')
end
end
- context 'when ref is nil' do
+ describe 'PATCH /projects/pipelines_schedules/:id/edit' do
before do
- pipeline_schedule.update_attribute(:ref, nil)
- visit_pipelines_schedules
+ edit_pipeline_schedule
end
- it 'shows a list of the pipeline schedules with empty ref column' do
- expect(first('.branch-name-cell').text).to eq('')
+ it 'it displays existing properties' do
+ description = find_field('schedule_description').value
+ expect(description).to eq('pipeline schedule')
+ expect(page).to have_button('master')
+ expect(page).to have_button('UTC')
end
- end
- end
- describe 'POST /projects/pipeline_schedules/new', js: true do
- let(:visit_page) { visit_new_pipeline_schedule }
+ it 'edits the scheduled pipeline' do
+ fill_in 'schedule_description', with: 'my brand new description'
- it 'sets defaults for timezone and target branch' do
- expect(page).to have_button('master')
- expect(page).to have_button('UTC')
- end
+ save_pipeline_schedule
+
+ expect(page).to have_content('my brand new description')
+ end
+
+ context 'when ref is nil' do
+ before do
+ pipeline_schedule.update_attribute(:ref, nil)
+ edit_pipeline_schedule
+ end
+
+ it 'shows the pipeline schedule with default ref' do
+ page.within('.js-target-branch-dropdown') do
+ expect(first('.dropdown-toggle-text').text).to eq('master')
+ end
+ end
+ end
- it 'it creates a new scheduled pipeline' do
- fill_in_schedule_form
- save_pipeline_schedule
+ context 'when ref is empty' do
+ before do
+ pipeline_schedule.update_attribute(:ref, '')
+ edit_pipeline_schedule
+ end
- expect(page).to have_content('my fancy description')
+ it 'shows the pipeline schedule with default ref' do
+ page.within('.js-target-branch-dropdown') do
+ expect(first('.dropdown-toggle-text').text).to eq('master')
+ end
+ end
+ end
end
- it 'it prevents an invalid form from being submitted' do
- save_pipeline_schedule
+ context 'when user creates a new pipeline schedule with variables' do
+ background do
+ visit_pipelines_schedules
+ click_link 'New schedule'
+ fill_in_schedule_form
+ all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA')
+ all('[name="schedule[variables_attributes][][value]"]')[0].set('AAA123')
+ all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB')
+ all('[name="schedule[variables_attributes][][value]"]')[1].set('BBB123')
+ save_pipeline_schedule
+ end
- expect(page).to have_content('This field is required')
+ scenario 'user sees the new variable in edit window' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.pipeline-variable-list') do
+ expect(find(".pipeline-variable-row:nth-child(1) .pipeline-variable-key-input").value).to eq('AAA')
+ expect(find(".pipeline-variable-row:nth-child(1) .pipeline-variable-value-input").value).to eq('AAA123')
+ expect(find(".pipeline-variable-row:nth-child(2) .pipeline-variable-key-input").value).to eq('BBB')
+ expect(find(".pipeline-variable-row:nth-child(2) .pipeline-variable-value-input").value).to eq('BBB123')
+ end
+ end
end
- end
- describe 'PATCH /projects/pipelines_schedules/:id/edit', js: true do
- let(:visit_page) do
- edit_pipeline_schedule
+ context 'when user edits a variable of a pipeline schedule' do
+ background do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ end
+
+ visit_pipelines_schedules
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ all('[name="schedule[variables_attributes][][key]"]')[0].set('foo')
+ all('[name="schedule[variables_attributes][][value]"]')[0].set('bar')
+ click_button 'Save pipeline schedule'
+ end
+
+ scenario 'user sees the updated variable in edit window' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.pipeline-variable-list') do
+ expect(find(".pipeline-variable-row:nth-child(1) .pipeline-variable-key-input").value).to eq('foo')
+ expect(find(".pipeline-variable-row:nth-child(1) .pipeline-variable-value-input").value).to eq('bar')
+ end
+ end
end
- it 'it displays existing properties' do
- description = find_field('schedule_description').value
- expect(description).to eq('pipeline schedule')
- expect(page).to have_button('master')
- expect(page).to have_button('UTC')
+ context 'when user removes a variable of a pipeline schedule' do
+ background do
+ create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule|
+ create(:ci_pipeline_schedule_variable, key: 'AAA', value: 'AAA123', pipeline_schedule: pipeline_schedule)
+ end
+
+ visit_pipelines_schedules
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ find('.pipeline-variable-list .pipeline-variable-row-remove-button').click
+ click_button 'Save pipeline schedule'
+ end
+
+ scenario 'user does not see the removed variable in edit window' do
+ find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click
+ page.within('.pipeline-variable-list') do
+ expect(find(".pipeline-variable-row:nth-child(1) .pipeline-variable-key-input").value).to eq('')
+ expect(find(".pipeline-variable-row:nth-child(1) .pipeline-variable-value-input").value).to eq('')
+ end
+ end
end
+ end
- it 'edits the scheduled pipeline' do
- fill_in 'schedule_description', with: 'my brand new description'
+ context 'logged in as non-member' do
+ before do
+ gitlab_sign_in(user)
+ end
- save_pipeline_schedule
+ describe 'GET /projects/pipeline_schedules' do
+ before do
+ visit_pipelines_schedules
+ end
- expect(page).to have_content('my brand new description')
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
+ end
+ end
end
+ end
- context 'when ref is nil' do
+ context 'not logged in' do
+ describe 'GET /projects/pipeline_schedules' do
before do
- pipeline_schedule.update_attribute(:ref, nil)
- edit_pipeline_schedule
+ visit_pipelines_schedules
end
- it 'shows the pipeline schedule with default ref' do
- page.within('.js-target-branch-dropdown') do
- expect(first('.dropdown-toggle-text').text).to eq('master')
+ describe 'The view' do
+ it 'does not show create schedule button' do
+ expect(page).not_to have_link('New schedule')
end
end
end
end
def visit_new_pipeline_schedule
- visit new_namespace_project_pipeline_schedule_path(project.namespace, project, pipeline_schedule)
+ visit new_project_pipeline_schedule_path(project, pipeline_schedule)
end
def edit_pipeline_schedule
- visit edit_namespace_project_pipeline_schedule_path(project.namespace, project, pipeline_schedule)
+ visit edit_project_pipeline_schedule_path(project, pipeline_schedule)
end
def visit_pipelines_schedules
- visit namespace_project_pipeline_schedules_path(project.namespace, project, scope: scope)
+ visit project_pipeline_schedules_path(project, scope: scope)
end
def select_timezone
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index ca8e4b67c2f..45b1d482c8a 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -1,13 +1,11 @@
require 'spec_helper'
-describe 'Pipeline', :feature, :js do
- include GitlabRoutingHelper
-
+describe 'Pipeline', :js do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :developer]
end
@@ -44,11 +42,11 @@ describe 'Pipeline', :feature, :js do
describe 'GET /:project/pipelines/:id' do
include_context 'pipeline builds'
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
before do
- visit namespace_project_pipeline_path(project.namespace, project, pipeline)
+ visit project_pipeline_path(project, pipeline)
end
it 'shows the pipeline graph' do
@@ -190,11 +188,11 @@ describe 'Pipeline', :feature, :js do
describe 'GET /:project/pipelines/:id/builds' do
include_context 'pipeline builds'
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
before do
- visit builds_namespace_project_pipeline_path(project.namespace, project, pipeline)
+ visit builds_project_pipeline_path(project, pipeline)
end
it 'shows a list of jobs' do
@@ -264,9 +262,9 @@ describe 'Pipeline', :feature, :js do
end
describe 'GET /:project/pipelines/:id/failures' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
- let(:pipeline_failures_page) { failures_namespace_project_pipeline_path(project.namespace, project, pipeline) }
+ let(:pipeline_failures_page) { failures_project_pipeline_path(project, pipeline) }
let!(:failed_build) { create(:ci_build, :failed, pipeline: pipeline) }
context 'with failed build' do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 5ff9b891e8a..f05d8685cfb 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
-describe 'Pipelines', :feature, :js do
+describe 'Pipelines', :js do
let(:project) { create(:empty_project) }
context 'when user is logged in' do
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :developer]
end
describe 'GET /:project/pipelines' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let!(:pipeline) do
create(
@@ -51,7 +51,7 @@ describe 'Pipelines', :feature, :js do
context 'header tabs' do
before do
- visit namespace_project_pipelines_path(project.namespace, project)
+ visit project_pipelines_path(project)
wait_for_requests
end
@@ -369,14 +369,14 @@ describe 'Pipelines', :feature, :js do
end
it 'should render pagination' do
- visit namespace_project_pipelines_path(project.namespace, project)
+ visit project_pipelines_path(project)
wait_for_requests
expect(page).to have_selector('.gl-pagination')
end
it 'should render second page of pipelines' do
- visit namespace_project_pipelines_path(project.namespace, project, page: '2')
+ visit project_pipelines_path(project, page: '2')
wait_for_requests
expect(page).to have_selector('.gl-pagination .page', count: 2)
@@ -385,7 +385,7 @@ describe 'Pipelines', :feature, :js do
end
describe 'GET /:project/pipelines/show' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_empty_pipeline,
@@ -405,7 +405,7 @@ describe 'Pipelines', :feature, :js do
create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3)
- visit namespace_project_pipeline_path(project.namespace, project, pipeline)
+ visit project_pipeline_path(project, pipeline)
wait_for_requests
end
@@ -437,10 +437,10 @@ describe 'Pipelines', :feature, :js do
end
describe 'POST /:project/pipelines' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
- visit new_namespace_project_pipeline_path(project.namespace, project)
+ visit new_project_pipeline_path(project)
end
context 'for valid commit', js: true do
@@ -476,10 +476,10 @@ describe 'Pipelines', :feature, :js do
end
describe 'Create pipelines' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
- visit new_namespace_project_pipeline_path(project.namespace, project)
+ visit new_project_pipeline_path(project)
end
describe 'new pipeline page' do
@@ -508,25 +508,25 @@ describe 'Pipelines', :feature, :js do
context 'when user is not logged in' do
before do
- visit namespace_project_pipelines_path(project.namespace, project)
+ visit project_pipelines_path(project)
end
context 'when project is public' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
it { expect(page).to have_content 'Build with confidence' }
it { expect(page).to have_http_status(:success) }
end
context 'when project is private' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:project, :private, :repository) }
it { expect(page).to have_content 'You need to sign in' }
end
end
def visit_project_pipelines(**query)
- visit namespace_project_pipelines_path(project.namespace, project, query)
+ visit project_pipelines_path(project, query)
wait_for_requests
end
end
diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb
index baa38ff8cca..6001bcfff0a 100644
--- a/spec/features/projects/project_settings_spec.rb
+++ b/spec/features/projects/project_settings_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
-describe 'Edit Project Settings', feature: true do
+describe 'Edit Project Settings' do
include Select2Helper
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace, path: 'gitlab', name: 'sample') }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'Project settings section', js: true do
it 'shows errors for invalid project name' do
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
fill_in 'project_name_edit', with: 'foo&bar'
click_button 'Save changes'
expect(page).to have_field 'project_name_edit', with: 'foo&bar'
@@ -21,7 +21,7 @@ describe 'Edit Project Settings', feature: true do
end
it 'shows a successful notice when the project is updated' do
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
fill_in 'project_name_edit', with: 'hello world'
click_button 'Save changes'
expect(page).to have_content "Project 'hello world' was successfully updated."
@@ -55,8 +55,7 @@ describe 'Edit Project Settings', feature: true do
end
context 'when changing project path' do
- # Not using empty project because we need a repo to exist
- let(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') }
+ let(:project) { create(:project, :repository, namespace: user.namespace, name: 'gitlabhq') }
before(:context) do
TestEnv.clean_test_path
@@ -75,7 +74,7 @@ describe 'Edit Project Settings', feature: true do
end
specify 'the project is accessible via a redirect from the old path' do
- old_path = namespace_project_path(project.namespace, project)
+ old_path = project_path(project)
rename_project(project, path: 'bar')
new_path = namespace_project_path(project.namespace, 'bar')
visit old_path
@@ -85,7 +84,7 @@ describe 'Edit Project Settings', feature: true do
context 'and a new project is added with the same path' do
it 'overrides the redirect' do
- old_path = namespace_project_path(project.namespace, project)
+ old_path = project_path(project)
rename_project(project, path: 'bar')
new_project = create(:empty_project, namespace: user.namespace, path: 'gitlabhq', name: 'quz')
visit old_path
@@ -97,8 +96,7 @@ describe 'Edit Project Settings', feature: true do
end
describe 'Transfer project section', js: true do
- # Not using empty project because we need a repo to exist
- let!(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') }
+ let!(:project) { create(:project, :repository, namespace: user.namespace, name: 'gitlabhq') }
let!(:group) { create(:group) }
before(:context) do
@@ -122,7 +120,7 @@ describe 'Edit Project Settings', feature: true do
end
specify 'the project is accessible via a redirect from the old path' do
- old_path = namespace_project_path(project.namespace, project)
+ old_path = project_path(project)
transfer_project(project, group)
new_path = namespace_project_path(group, project)
visit old_path
@@ -132,7 +130,7 @@ describe 'Edit Project Settings', feature: true do
context 'and a new project is added with the same path' do
it 'overrides the redirect' do
- old_path = namespace_project_path(project.namespace, project)
+ old_path = project_path(project)
transfer_project(project, group)
new_project = create(:empty_project, namespace: user.namespace, path: 'gitlabhq', name: 'quz')
visit old_path
@@ -144,7 +142,7 @@ describe 'Edit Project Settings', feature: true do
end
def rename_project(project, name: nil, path: nil)
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
fill_in('project_name', with: name) if name
fill_in('Path', with: path) if path
click_button('Rename project')
@@ -153,7 +151,7 @@ def rename_project(project, name: nil, path: nil)
end
def transfer_project(project, namespace)
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
select2(namespace.id, from: '#new_namespace_id')
click_button('Transfer project')
confirm_transfer_modal
diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb
index 016a992bdcf..f0a23729220 100644
--- a/spec/features/projects/ref_switcher_spec.rb
+++ b/spec/features/projects/ref_switcher_spec.rb
@@ -1,13 +1,13 @@
require 'rails_helper'
-feature 'Ref switcher', feature: true, js: true do
+feature 'Ref switcher', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_tree_path(project.namespace, project, 'master')
+ sign_in(user)
+ visit project_tree_path(project, 'master')
end
it 'allow user to change ref by enter key' do
@@ -19,14 +19,14 @@ feature 'Ref switcher', feature: true, js: true do
input.set 'binary'
wait_for_requests
- expect(find('.dropdown-content ul')).to have_selector('li', count: 6)
+ expect(find('.dropdown-content ul')).to have_selector('li', count: 7)
page.within '.dropdown-content ul' do
input.native.send_keys :enter
end
end
- expect(page).to have_title 'binary-encoding'
+ expect(page).to have_title 'add-pdf-text-binary'
end
it "user selects ref with special characters" do
diff --git a/spec/features/projects/services/jira_service_spec.rb b/spec/features/projects/services/jira_service_spec.rb
index 17f6320d52a..645713d0805 100644
--- a/spec/features/projects/services/jira_service_spec.rb
+++ b/spec/features/projects/services/jira_service_spec.rb
@@ -1,18 +1,17 @@
require 'spec_helper'
-feature 'Setup Jira service', :feature, :js do
+feature 'Setup Jira service', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:service) { project.create_jira_service }
let(:url) { 'http://jira.example.com' }
- let(:project_url) { 'http://username:password@jira.example.com/rest/api/2/project/GitLabProject' }
+ let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' }
def fill_form(active = true)
check 'Active' if active
fill_in 'service_url', with: url
- fill_in 'service_project_key', with: 'GitLabProject'
fill_in 'service_username', with: 'username'
fill_in 'service_password', with: 'password'
fill_in 'service_jira_issue_transition_id', with: '25'
@@ -20,33 +19,28 @@ feature 'Setup Jira service', :feature, :js do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_settings_integrations_path(project.namespace, project)
+ visit project_settings_integrations_path(project)
end
describe 'user sets and activates Jira Service' do
context 'when Jira connection test succeeds' do
- before do
- WebMock.stub_request(:get, project_url)
- end
-
it 'activates the JIRA service' do
+ server_info = { key: 'value' }.to_json
+ WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info)
+
click_link('JIRA')
fill_form
click_button('Test settings and save changes')
wait_for_requests
expect(page).to have_content('JIRA activated.')
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
end
end
context 'when Jira connection test fails' do
- before do
- WebMock.stub_request(:get, project_url).to_return(status: 401)
- end
-
it 'shows errors when some required fields are not filled in' do
click_link('JIRA')
@@ -60,19 +54,22 @@ feature 'Setup Jira service', :feature, :js do
end
it 'activates the JIRA service' do
+ WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password))
+ .to_raise(JIRA::HTTPError.new(double(message: 'message')))
+
click_link('JIRA')
fill_form
click_button('Test settings and save changes')
wait_for_requests
- expect(find('.flash-container-page')).to have_content 'Test failed.'
+ expect(find('.flash-container-page')).to have_content 'Test failed. message'
expect(find('.flash-container-page')).to have_content 'Save anyway'
find('.flash-alert .flash-action').click
wait_for_requests
expect(page).to have_content('JIRA activated.')
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
end
end
end
@@ -85,7 +82,7 @@ feature 'Setup Jira service', :feature, :js do
click_button('Save changes')
expect(page).to have_content('JIRA settings saved, but not activated.')
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
end
end
end
diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb
index d87985f1c92..134d7e5e8b7 100644
--- a/spec/features/projects/services/mattermost_slash_command_spec.rb
+++ b/spec/features/projects/services/mattermost_slash_command_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Setup Mattermost slash commands', :feature, :js do
+feature 'Setup Mattermost slash commands', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:service) { project.create_mattermost_slash_commands_service }
@@ -9,8 +9,8 @@ feature 'Setup Mattermost slash commands', :feature, :js do
before do
stub_mattermost_setting(enabled: mattermost_enabled)
project.team << [user, :master]
- gitlab_sign_in(user)
- visit edit_namespace_project_service_path(project.namespace, project, service)
+ sign_in(user)
+ visit edit_project_service_path(project, service)
end
describe 'user visits the mattermost slash command config page' do
@@ -30,7 +30,7 @@ feature 'Setup Mattermost slash commands', :feature, :js do
fill_in 'service_token', with: token
click_on 'Save changes'
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
expect(page).to have_content('Mattermost slash commands settings saved, but not activated.')
end
@@ -41,7 +41,7 @@ feature 'Setup Mattermost slash commands', :feature, :js do
check 'service_active'
click_on 'Save changes'
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
expect(page).to have_content('Mattermost slash commands activated.')
end
@@ -159,7 +159,7 @@ feature 'Setup Mattermost slash commands', :feature, :js do
it 'shows the correct trigger url' do
value = find_field('request_url').value
- expect(value).to match("api/v3/projects/#{project.id}/services/mattermost_slash_commands/trigger")
+ expect(value).to match("api/v4/projects/#{project.id}/services/mattermost_slash_commands/trigger")
end
it 'shows a token placeholder' do
diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb
index 50707e6a49f..824cae261e0 100644
--- a/spec/features/projects/services/slack_service_spec.rb
+++ b/spec/features/projects/services/slack_service_spec.rb
@@ -1,19 +1,19 @@
require 'spec_helper'
-feature 'Projects > Slack service > Setup events', feature: true do
+feature 'Projects > Slack service > Setup events' do
let(:user) { create(:user) }
let(:service) { SlackService.new }
- let(:project) { create(:project, slack_service: service) }
+ let(:project) { create(:empty_project, slack_service: service) }
background do
service.fields
service.update_attributes(push_channel: 1, issue_channel: 2, merge_request_channel: 3, note_channel: 4, tag_push_channel: 5, pipeline_channel: 6, wiki_page_channel: 7)
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'user can filter events by channel' do
- visit edit_namespace_project_service_path(project.namespace, project, service)
+ visit edit_project_service_path(project, service)
expect(page.find_field("service_push_channel").value).to have_content '1'
expect(page.find_field("service_issue_channel").value).to have_content '2'
diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb
index 3fae38c1799..6002c589fba 100644
--- a/spec/features/projects/services/slack_slash_command_spec.rb
+++ b/spec/features/projects/services/slack_slash_command_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-feature 'Slack slash commands', feature: true do
+feature 'Slack slash commands' do
given(:user) { create(:user) }
- given(:project) { create(:project) }
+ given(:project) { create(:empty_project) }
given(:service) { project.create_slack_slash_commands_service }
background do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit edit_namespace_project_service_path(project.namespace, project, service)
+ sign_in(user)
+ visit edit_project_service_path(project, service)
end
it 'shows a token placeholder' do
@@ -25,7 +25,7 @@ feature 'Slack slash commands', feature: true do
fill_in 'service_token', with: 'token'
click_on 'Save'
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
expect(page).to have_content('Slack slash commands settings saved, but not activated.')
end
@@ -34,12 +34,12 @@ feature 'Slack slash commands', feature: true do
check 'service_active'
click_on 'Save'
- expect(current_path).to eq(namespace_project_settings_integrations_path(project.namespace, project))
+ expect(current_path).to eq(project_settings_integrations_path(project))
expect(page).to have_content('Slack slash commands activated.')
end
it 'shows the correct trigger url' do
value = find_field('url').value
- expect(value).to match("api/v3/projects/#{project.id}/services/slack_slash_commands/trigger")
+ expect(value).to match("api/v4/projects/#{project.id}/services/slack_slash_commands/trigger")
end
end
diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb
index a59374b37ea..1de4918e142 100644
--- a/spec/features/projects/settings/integration_settings_spec.rb
+++ b/spec/features/projects/settings/integration_settings_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Integration settings', feature: true do
+feature 'Integration settings' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:role) { :developer }
- let(:integrations_path) { namespace_project_settings_integrations_path(project.namespace, project) }
+ let(:integrations_path) { project_settings_integrations_path(project) }
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
end
@@ -36,14 +36,14 @@ feature 'Integration settings', feature: true do
expect(page.status_code).to eq(200)
expect(page).to have_content(hook.url)
expect(page).to have_content('SSL Verification: enabled')
- expect(page).to have_content('Push Events')
- expect(page).to have_content('Tag Push Events')
- expect(page).to have_content('Issues Events')
- expect(page).to have_content('Confidential Issues Events')
- expect(page).to have_content('Note Events')
- expect(page).to have_content('Merge Requests Events')
- expect(page).to have_content('Pipeline Events')
- expect(page).to have_content('Wiki Page Events')
+ expect(page).to have_content('Push events')
+ expect(page).to have_content('Tag push events')
+ expect(page).to have_content('Issues events')
+ expect(page).to have_content('Confidential issues events')
+ expect(page).to have_content('Note events')
+ expect(page).to have_content('Merge requests events')
+ expect(page).to have_content('Pipeline events')
+ expect(page).to have_content('Wiki page events')
end
scenario 'create webhook' do
@@ -58,8 +58,8 @@ feature 'Integration settings', feature: true do
expect(page).to have_content(url)
expect(page).to have_content('SSL Verification: enabled')
- expect(page).to have_content('Push Events')
- expect(page).to have_content('Tag Push Events')
+ expect(page).to have_content('Push events')
+ expect(page).to have_content('Tag push events')
expect(page).to have_content('Job events')
end
@@ -76,11 +76,12 @@ feature 'Integration settings', feature: true do
expect(page).to have_content(url)
end
- scenario 'test existing webhook' do
+ scenario 'test existing webhook', js: true do
WebMock.stub_request(:post, hook.url)
visit integrations_path
- click_link 'Test'
+ find('.hook-test-button.dropdown').click
+ click_link 'Push events'
expect(current_path).to eq(integrations_path)
end
@@ -109,7 +110,7 @@ feature 'Integration settings', feature: true do
scenario 'show list of hook logs' do
hook_log
- visit edit_namespace_project_hook_path(project.namespace, project, hook)
+ visit edit_project_hook_path(project, hook)
expect(page).to have_content('Recent Deliveries')
expect(page).to have_content(hook_log.url)
@@ -117,7 +118,7 @@ feature 'Integration settings', feature: true do
scenario 'show hook log details' do
hook_log
- visit edit_namespace_project_hook_path(project.namespace, project, hook)
+ visit edit_project_hook_path(project, hook)
click_link 'View details'
expect(page).to have_content("POST #{hook_log.url}")
@@ -129,11 +130,11 @@ feature 'Integration settings', feature: true do
WebMock.stub_request(:post, hook.url)
hook_log
- visit edit_namespace_project_hook_path(project.namespace, project, hook)
+ visit edit_project_hook_path(project, hook)
click_link 'View details'
click_link 'Resend Request'
- expect(current_path).to eq(edit_namespace_project_hook_path(project.namespace, project, hook))
+ expect(current_path).to eq(edit_project_hook_path(project, hook))
end
end
end
diff --git a/spec/features/projects/settings/merge_requests_settings_spec.rb b/spec/features/projects/settings/merge_requests_settings_spec.rb
index f2af14ceab2..796e2026905 100644
--- a/spec/features/projects/settings/merge_requests_settings_spec.rb
+++ b/spec/features/projects/settings/merge_requests_settings_spec.rb
@@ -1,14 +1,12 @@
require 'spec_helper'
-feature 'Project settings > Merge Requests', feature: true, js: true do
- include GitlabRoutingHelper
-
+feature 'Project settings > Merge Requests', :js do
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
background do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when Merge Request and Pipelines are initially enabled' do
diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb
index c33fbd49d21..f24d7ff64d0 100644
--- a/spec/features/projects/settings/pipelines_settings_spec.rb
+++ b/spec/features/projects/settings/pipelines_settings_spec.rb
@@ -1,16 +1,14 @@
require 'spec_helper'
-feature "Pipelines settings", feature: true do
- include GitlabRoutingHelper
-
+feature "Pipelines settings" do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:role) { :developer }
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
- visit namespace_project_pipelines_settings_path(project.namespace, project)
+ visit project_pipelines_settings_path(project)
end
context 'for developer' do
diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb
index 35cd0d6e832..15180d4b498 100644
--- a/spec/features/projects/settings/repository_settings_spec.rb
+++ b/spec/features/projects/settings/repository_settings_spec.rb
@@ -1,20 +1,20 @@
require 'spec_helper'
-feature 'Repository settings', feature: true do
+feature 'Repository settings' do
let(:project) { create(:project_empty_repo) }
let(:user) { create(:user) }
let(:role) { :developer }
background do
project.team << [user, role]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'for developer' do
given(:role) { :developer }
scenario 'is not allowed to view' do
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
expect(page.status_code).to eq(404)
end
@@ -32,7 +32,7 @@ feature 'Repository settings', feature: true do
project.deploy_keys << private_deploy_key
project.deploy_keys << public_deploy_key
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
expect(page.status_code).to eq(200)
expect(page).to have_content('private_deploy_key')
@@ -40,7 +40,7 @@ feature 'Repository settings', feature: true do
end
scenario 'add a new deploy key' do
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
fill_in 'deploy_key_title', with: 'new_deploy_key'
fill_in 'deploy_key_key', with: new_ssh_key
@@ -53,7 +53,7 @@ feature 'Repository settings', feature: true do
scenario 'edit an existing deploy key' do
project.deploy_keys << private_deploy_key
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
find('li', text: private_deploy_key.title).click_link('Edit')
@@ -70,7 +70,7 @@ feature 'Repository settings', feature: true do
project2.team << [user, role]
project2.deploy_keys << private_deploy_key
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
find('li', text: private_deploy_key.title).click_link('Edit')
@@ -84,7 +84,7 @@ feature 'Repository settings', feature: true do
scenario 'remove an existing deploy key' do
project.deploy_keys << private_deploy_key
- visit namespace_project_settings_repository_path(project.namespace, project)
+ visit project_settings_repository_path(project)
find('li', text: private_deploy_key.title).click_button('Remove')
diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb
index 18c71dee41b..1e705d211ea 100644
--- a/spec/features/projects/settings/visibility_settings_spec.rb
+++ b/spec/features/projects/settings/visibility_settings_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Visibility settings', feature: true, js: true do
+feature 'Visibility settings', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace, visibility_level: 20) }
+ let(:project) { create(:empty_project, namespace: user.namespace, visibility_level: 20) }
context 'as owner' do
before do
- gitlab_sign_in(user)
- visit edit_namespace_project_path(project.namespace, project)
+ sign_in(user)
+ visit edit_project_path(project)
end
scenario 'project visibility select is available' do
@@ -32,8 +32,8 @@ feature 'Visibility settings', feature: true, js: true do
before do
project.team << [master_user, :master]
- gitlab_sign_in(master_user)
- visit edit_namespace_project_path(project.namespace, project)
+ sign_in(master_user)
+ visit edit_project_path(project)
end
scenario 'project visibility is locked' do
diff --git a/spec/features/projects/shortcuts_spec.rb b/spec/features/projects/shortcuts_spec.rb
index cec79277c33..2c6d0a56311 100644
--- a/spec/features/projects/shortcuts_spec.rb
+++ b/spec/features/projects/shortcuts_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-feature 'Project shortcuts', feature: true do
- let(:project) { create(:project, name: 'Victorialand') }
+feature 'Project shortcuts' do
+ let(:project) { create(:empty_project, name: 'Victorialand') }
let(:user) { create(:user) }
describe 'On a project', js: true do
before do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_path(project.namespace, project)
+ sign_in user
+ visit project_path(project)
end
describe 'pressing "i"' do
diff --git a/spec/features/projects/show_project_spec.rb b/spec/features/projects/show_project_spec.rb
new file mode 100644
index 00000000000..1bc6fae9e7f
--- /dev/null
+++ b/spec/features/projects/show_project_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe 'Project show page', feature: true do
+ context 'when project pending delete' do
+ let(:project) { create(:project, :empty_repo, pending_delete: true) }
+
+ before do
+ sign_in(project.owner)
+ end
+
+ it 'shows error message if deletion for project fails' do
+ project.update_attributes(delete_error: "Something went wrong", pending_delete: false)
+
+ visit project_path(project)
+
+ expect(page).to have_selector('.project-deletion-failed-message')
+ expect(page).to have_content("This project was scheduled for deletion, but failed with the following message: #{project.delete_error}")
+ end
+ end
+end
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index c75d6dbc307..7f0e7e3116c 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-feature 'Create Snippet', :js, feature: true do
+feature 'Create Snippet', :js do
include DropzoneHelper
let(:user) { create(:user) }
- let(:project) { create(:project, :repository, :public) }
+ let(:project) { create(:empty_project, :public) }
def fill_form
fill_in 'project_snippet_title', with: 'My Snippet Title'
@@ -17,9 +17,9 @@ feature 'Create Snippet', :js, feature: true do
context 'when a user is authenticated' do
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_snippets_path(project.namespace, project)
+ visit project_snippets_path(project)
click_on('New snippet')
end
@@ -77,7 +77,7 @@ feature 'Create Snippet', :js, feature: true do
it 'shows a public snippet on the index page but not the New snippet button' do
snippet = create(:project_snippet, :public, project: project)
- visit namespace_project_snippets_path(project.namespace, project)
+ visit project_snippets_path(project)
expect(page).to have_content(snippet.title)
expect(page).not_to have_content('New snippet')
diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb
index 9e73ba4123b..08dc7cf6c5b 100644
--- a/spec/features/projects/snippets/show_spec.rb
+++ b/spec/features/projects/snippets/show_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Project snippet', :js, feature: true do
+feature 'Project snippet', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'Ruby file' do
@@ -15,7 +15,7 @@ feature 'Project snippet', :js, feature: true do
let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
before do
- visit namespace_project_snippet_path(project.namespace, project, snippet)
+ visit project_snippet_path(project, snippet)
wait_for_requests
end
@@ -46,7 +46,7 @@ feature 'Project snippet', :js, feature: true do
context 'visiting directly' do
before do
- visit namespace_project_snippet_path(project.namespace, project, snippet)
+ visit project_snippet_path(project, snippet)
wait_for_requests
end
@@ -118,7 +118,7 @@ feature 'Project snippet', :js, feature: true do
context 'visiting with a line number anchor' do
before do
- visit namespace_project_snippet_path(project.namespace, project, snippet, anchor: 'L1')
+ visit project_snippet_path(project, snippet, anchor: 'L1')
wait_for_requests
end
diff --git a/spec/features/projects/snippets_spec.rb b/spec/features/projects/snippets_spec.rb
index 80dbffaffc7..0822684a42c 100644
--- a/spec/features/projects/snippets_spec.rb
+++ b/spec/features/projects/snippets_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Project snippets', :js, feature: true do
+describe 'Project snippets', :js do
context 'when the project has snippets' do
let(:project) { create(:empty_project, :public) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
@@ -10,7 +10,7 @@ describe 'Project snippets', :js, feature: true do
before do
allow(Snippet).to receive(:default_per_page).and_return(1)
- visit namespace_project_snippets_path(project.namespace, project)
+ visit project_snippets_path(project)
end
it_behaves_like 'paginated snippets'
@@ -18,7 +18,7 @@ describe 'Project snippets', :js, feature: true do
context 'list content' do
it 'contains all project snippets' do
- visit namespace_project_snippets_path(project.namespace, project)
+ visit project_snippets_path(project)
expect(page).to have_selector('.snippet-row', count: 2)
@@ -29,8 +29,8 @@ describe 'Project snippets', :js, feature: true do
context 'when submitting a note' do
before do
- gitlab_sign_in :admin
- visit namespace_project_snippet_path(project.namespace, project, snippets[0])
+ sign_in(create(:admin))
+ visit project_snippet_path(project, snippets[0])
end
it 'should have autocomplete' do
diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb
index 63eb97d5a92..262dcc0abff 100644
--- a/spec/features/projects/sub_group_issuables_spec.rb
+++ b/spec/features/projects/sub_group_issuables_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Subgroup Issuables', :feature, :js, :nested_groups do
+describe 'Subgroup Issuables', :js, :nested_groups do
let!(:group) { create(:group, name: 'group') }
let!(:subgroup) { create(:group, parent: group, name: 'subgroup') }
let!(:project) { create(:empty_project, namespace: subgroup, name: 'project') }
@@ -8,17 +8,17 @@ describe 'Subgroup Issuables', :feature, :js, :nested_groups do
before do
project.add_master(user)
- gitlab_sign_in user
+ sign_in user
end
it 'shows the full subgroup title when issues index page is empty' do
- visit namespace_project_issues_path(project.namespace.to_param, project.to_param)
+ visit project_issues_path(project)
expect_to_have_full_subgroup_title
end
it 'shows the full subgroup title when merge requests index page is empty' do
- visit namespace_project_merge_requests_path(project.namespace.to_param, project.to_param)
+ visit project_merge_requests_path(project)
expect_to_have_full_subgroup_title
end
diff --git a/spec/features/projects/tags/download_buttons_spec.rb b/spec/features/projects/tags/download_buttons_spec.rb
index ca00a51aa3c..a6c5a486bcc 100644
--- a/spec/features/projects/tags/download_buttons_spec.rb
+++ b/spec/features/projects/tags/download_buttons_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Download buttons in tags page', feature: true do
+feature 'Download buttons in tags page' do
given(:user) { create(:user) }
given(:role) { :developer }
given(:status) { 'success' }
@@ -23,20 +23,18 @@ feature 'Download buttons in tags page', feature: true do
end
background do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, role]
end
describe 'when checking tags' do
context 'with artifacts' do
before do
- visit namespace_project_tags_path(project.namespace, project)
+ visit project_tags_path(project)
end
scenario 'shows download artifacts button' do
- href = latest_succeeded_namespace_project_artifacts_path(
- project.namespace, project, "#{tag}/download",
- job: 'build')
+ href = latest_succeeded_project_artifacts_path(project, "#{tag}/download", job: 'build')
expect(page).to have_link "Download '#{build.name}'", href: href
end
diff --git a/spec/features/projects/tree/rss_spec.rb b/spec/features/projects/tree/rss_spec.rb
index 135584e5bf8..4f2e0a76a65 100644
--- a/spec/features/projects/tree/rss_spec.rb
+++ b/spec/features/projects/tree/rss_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
feature 'Project Tree RSS' do
+ let(:user) { create(:user) }
let(:project) { create(:project, :repository, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
- let(:path) { namespace_project_tree_path(project.namespace, project, :master) }
+ let(:path) { project_tree_path(project, :master) }
context 'when signed in' do
before do
- user = create(:user)
project.team << [user, :developer]
- gitlab_sign_in(user)
+ sign_in(user)
visit path
end
diff --git a/spec/features/projects/user_browses_files_spec.rb b/spec/features/projects/user_browses_files_spec.rb
new file mode 100644
index 00000000000..b7a0b72db50
--- /dev/null
+++ b/spec/features/projects/user_browses_files_spec.rb
@@ -0,0 +1,188 @@
+require 'spec_helper'
+
+describe 'User browses files' do
+ include DropzoneHelper
+
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository, name: 'Shop') }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:tree_path_ref_6d39438) { project_tree_path(project, '6d39438') }
+ let(:tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ end
+
+ context 'when browsing the master branch' do
+ before do
+ visit(tree_path_root_ref)
+ end
+
+ it 'shows files from a repository' do
+ expect(page).to have_content('VERSION')
+ expect(page).to have_content('.gitignore')
+ expect(page).to have_content('LICENSE')
+ end
+
+ it 'shows the "Browse Directory" link' do
+ click_link('files')
+ click_link('History')
+
+ expect(page).to have_link('Browse Directory')
+ expect(page).not_to have_link('Browse Code')
+ end
+
+ it 'shows the "Browse File" link' do
+ page.within('.tree-table') do
+ click_link('README.md')
+ end
+ click_link('History')
+
+ expect(page).to have_link('Browse File')
+ expect(page).not_to have_link('Browse Files')
+ end
+
+ it 'shows the "Browse Code" link' do
+ click_link('History')
+
+ expect(page).to have_link('Browse Files')
+ expect(page).not_to have_link('Browse Directory')
+ end
+
+ it 'redirects to the permalink URL' do
+ click_link('.gitignore')
+ click_link('Permalink')
+
+ permalink_path = project_blob_path(project, "#{project.repository.commit.sha}/.gitignore")
+
+ expect(current_path).to eq(permalink_path)
+ end
+ end
+
+ context 'when browsing a specific ref' do
+ before do
+ visit(tree_path_ref_6d39438)
+ end
+
+ it 'shows files from a repository for "6d39438"' do
+ expect(current_path).to eq(tree_path_ref_6d39438)
+ expect(page).to have_content('.gitignore')
+ expect(page).to have_content('LICENSE')
+ end
+
+ it 'shows files from a repository with apostroph in its name', js: true do
+ first('.js-project-refs-dropdown').click
+
+ page.within('.project-refs-form') do
+ click_link("'test'")
+ end
+
+ expect(page).to have_selector('.dropdown-toggle-text', text: "'test'")
+
+ visit(project_tree_path(project, "'test'"))
+
+ expect(page).to have_css('.tree-commit-link', visible: true)
+ expect(page).not_to have_content('Loading commit data...')
+ end
+
+ it 'shows the code with a leading dot in the directory', js: true do
+ first('.js-project-refs-dropdown').click
+
+ page.within('.project-refs-form') do
+ click_link('fix')
+ end
+
+ visit(project_tree_path(project, 'fix/.testdir'))
+
+ expect(page).to have_css('.tree-commit-link', visible: true)
+ expect(page).not_to have_content('Loading commit data...')
+ end
+
+ it 'does not show the permalink link' do
+ click_link('.gitignore')
+
+ expect(page).not_to have_link('permalink')
+ end
+ end
+
+ context 'when browsing a file content' do
+ before do
+ visit(tree_path_root_ref)
+ click_link('.gitignore')
+ end
+
+ it 'shows a file content', js: true do
+ wait_for_requests
+ expect(page).to have_content('*.rbc')
+ end
+ end
+
+ context 'when browsing a raw file' do
+ before do
+ visit(project_blob_path(project, File.join(RepoHelpers.sample_commit.id, RepoHelpers.sample_blob.path)))
+ end
+
+ it 'shows a raw file content' do
+ click_link('Open raw')
+ expect(source).to eq('') # Body is filled in by gitlab-workhorse
+ end
+ end
+
+ context 'when browsing an LFS object' do
+ before do
+ allow_any_instance_of(Project).to receive(:lfs_enabled?).and_return(true)
+ visit(project_tree_path(project, 'lfs'))
+ end
+
+ it 'shows an LFS object' do
+ click_link('files')
+ click_link('lfs')
+ click_link('lfs_object.iso')
+
+ expect(page).to have_content('Download (1.5 MB)')
+ expect(page).not_to have_content('version https://git-lfs.github.com/spec/v1')
+ expect(page).not_to have_content('oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897')
+ expect(page).not_to have_content('size 1575078')
+
+ page.within('.content') do
+ expect(page).to have_content('Delete')
+ expect(page).to have_content('History')
+ expect(page).to have_content('Permalink')
+ expect(page).to have_content('Replace')
+ expect(page).not_to have_content('Annotate')
+ expect(page).not_to have_content('Blame')
+ expect(page).not_to have_content('Edit')
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'when previewing a file content' do
+ before do
+ visit(tree_path_root_ref)
+ end
+
+ it 'shows a preview of a file content', js: true do
+ find('.add-to-tree').click
+ click_link('Upload file')
+ drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'logo_sample.svg'))
+
+ page.within('#modal-upload-blob') do
+ fill_in(:commit_message, with: 'New commit message')
+ end
+
+ fill_in(:branch_name, with: 'new_branch_name', visible: true)
+ click_button('Upload file')
+
+ visit(project_blob_path(project, 'new_branch_name/logo_sample.svg'))
+
+ expect(page).to have_css('.file-content img')
+ end
+ end
+end
diff --git a/spec/features/projects/user_create_dir_spec.rb b/spec/features/projects/user_create_dir_spec.rb
deleted file mode 100644
index f375e1215db..00000000000
--- a/spec/features/projects/user_create_dir_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require 'spec_helper'
-
-feature 'New directory creation', feature: true, js: true do
- given(:user) { create(:user) }
- given(:role) { :developer }
- given(:project) { create(:project) }
-
- background do
- gitlab_sign_in(user)
- project.team << [user, role]
- visit namespace_project_tree_path(project.namespace, project, 'master')
- open_new_directory_modal
- fill_in 'dir_name', with: 'new_directory'
- end
-
- def open_new_directory_modal
- first('.add-to-tree').click
- click_link 'New directory'
- end
-
- def create_directory
- click_button 'Create directory'
- end
-
- context 'with default target branch' do
- background do
- create_directory
- end
-
- scenario 'creates the directory in the default branch' do
- expect(page).to have_content 'master'
- expect(page).to have_content 'The directory has been successfully created'
- expect(page).to have_content 'new_directory'
- end
- end
-
- context 'with a new target branch' do
- given(:new_branch_name) { 'new-feature' }
-
- background do
- fill_in :branch_name, with: new_branch_name
- create_directory
- end
-
- scenario 'creates the directory in the new branch' do
- expect(page).to have_content new_branch_name
- expect(page).to have_content 'The directory has been successfully created'
- end
-
- scenario 'redirects to the merge request' do
- expect(page).to have_content 'New Merge Request'
- expect(page).to have_content "From #{new_branch_name} into master"
- expect(page).to have_content 'Add new directory'
- expect(current_path).to eq(new_namespace_project_merge_request_path(project.namespace, project))
- end
- end
-end
diff --git a/spec/features/projects/user_creates_directory_spec.rb b/spec/features/projects/user_creates_directory_spec.rb
new file mode 100644
index 00000000000..1ba5d83eadf
--- /dev/null
+++ b/spec/features/projects/user_creates_directory_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+feature 'User creates a directory', js: true do
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository) }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :developer]
+ sign_in(user)
+ visit project_tree_path(project, 'master')
+ end
+
+ context 'with default target branch' do
+ before do
+ first('.add-to-tree').click
+ click_link('New directory')
+ end
+
+ it 'creates the directory in the default branch' do
+ fill_in(:dir_name, with: 'new_directory')
+ click_button('Create directory')
+
+ expect(page).to have_content('master')
+ expect(page).to have_content('The directory has been successfully created')
+ expect(page).to have_content('new_directory')
+ end
+
+ it 'does not create a directory with a name of already existed directory' do
+ fill_in(:dir_name, with: 'files')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Create directory')
+
+ expect(page).to have_content('A directory with this name already exists')
+ expect(current_path).to eq(project_tree_path(project, 'master'))
+ end
+ end
+
+ context 'with a new target branch' do
+ before do
+ first('.add-to-tree').click
+ click_link('New directory')
+ fill_in(:dir_name, with: 'new_directory')
+ fill_in(:branch_name, with: 'new-feature')
+ click_button('Create directory')
+ end
+
+ it 'creates the directory in the new branch and redirect to the merge request' do
+ expect(page).to have_content('new-feature')
+ expect(page).to have_content('The directory has been successfully created')
+ expect(page).to have_content('New Merge Request')
+ expect(page).to have_content('From new-feature into master')
+ expect(page).to have_content('Add new directory')
+
+ expect(current_path).to eq(project_new_merge_request_path(project))
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'creates a directory in a forked project' do
+ find('.add-to-tree').click
+ click_link('New directory')
+
+ expect(page).to have_content(fork_message)
+
+ find('.add-to-tree').click
+ click_link('New directory')
+ fill_in(:dir_name, with: 'new_directory')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Create directory')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+ end
+ end
+end
diff --git a/spec/features/projects/user_creates_files_spec.rb b/spec/features/projects/user_creates_files_spec.rb
new file mode 100644
index 00000000000..4b78cc4fc53
--- /dev/null
+++ b/spec/features/projects/user_creates_files_spec.rb
@@ -0,0 +1,153 @@
+require 'spec_helper'
+
+describe 'User creates files' do
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository, name: 'Shop') }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ end
+
+ context 'without commiting a new file' do
+ context 'when an user has write access' do
+ before do
+ visit(project_tree_path_root_ref)
+ end
+
+ it 'opens new file page' do
+ find('.add-to-tree').click
+ click_link('New file')
+
+ expect(page).to have_content('New file')
+ expect(page).to have_content('Commit message')
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'opens new file page on a forked project' do
+ find('.add-to-tree').click
+ click_link('New file')
+
+ expect(page).to have_selector('.file-editor')
+ expect(page).to have_content(fork_message)
+ expect(page).to have_content('New file')
+ expect(page).to have_content('Commit message')
+ end
+ end
+ end
+
+ context 'with commiting a new file' do
+ context 'when an user has write access' do
+ before do
+ visit(project_tree_path_root_ref)
+
+ find('.add-to-tree').click
+ click_link('New file')
+ end
+
+ it 'creates and commit a new file', js: true do
+ expect(page).to have_selector('.file-editor')
+
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ fill_in(:file_name, with: 'not_a_file.md')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ new_file_path = project_blob_path(project, 'master/not_a_file.md')
+
+ expect(current_path).to eq(new_file_path)
+
+ wait_for_requests
+
+ expect(page).to have_content('*.rbca')
+ end
+
+ it 'creates and commit a new file with new lines at the end of file', js: true do
+ execute_script('ace.edit("editor").setValue("Sample\n\n\n")')
+ fill_in(:file_name, with: 'not_a_file.md')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ new_file_path = project_blob_path(project, 'master/not_a_file.md')
+
+ expect(current_path).to eq(new_file_path)
+
+ find('.js-edit-blob').click
+
+ expect(evaluate_script('ace.edit("editor").getValue()')).to eq("Sample\n\n\n")
+ end
+
+ it 'creates and commit a new file with a directory name', js: true do
+ fill_in(:file_name, with: 'foo/bar/baz.txt')
+
+ expect(page).to have_selector('.file-editor')
+
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ expect(current_path).to eq(project_blob_path(project, 'master/foo/bar/baz.txt'))
+
+ wait_for_requests
+
+ expect(page).to have_content('*.rbca')
+ end
+
+ it 'creates and commit a new file specifying a new branch', js: true do
+ expect(page).to have_selector('.file-editor')
+
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ fill_in(:file_name, with: 'not_a_file.md')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ fill_in(:branch_name, with: 'new_branch_name', visible: true)
+ click_button('Commit changes')
+
+ expect(current_path).to eq(project_new_merge_request_path(project))
+
+ click_link('Changes')
+
+ wait_for_requests
+
+ expect(page).to have_content('*.rbca')
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'creates and commit new file in forked project', js: true do
+ find('.add-to-tree').click
+ click_link('New file')
+
+ expect(page).to have_selector('.file-editor')
+
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+
+ fill_in(:file_name, with: 'not_a_file.md')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+ expect(page).to have_content('New commit message')
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/user_creates_project_spec.rb b/spec/features/projects/user_creates_project_spec.rb
index 29f1eb8d73e..1c3791f63ac 100644
--- a/spec/features/projects/user_creates_project_spec.rb
+++ b/spec/features/projects/user_creates_project_spec.rb
@@ -18,7 +18,7 @@ feature 'User creates a project', js: true do
project = Project.last
- expect(current_path).to eq(namespace_project_path(project.namespace, project))
+ expect(current_path).to eq(project_path(project))
expect(page).to have_content('Empty')
expect(page).to have_content('git init')
expect(page).to have_content('git remote')
diff --git a/spec/features/projects/user_deletes_files_spec.rb b/spec/features/projects/user_deletes_files_spec.rb
new file mode 100644
index 00000000000..95cd316be0e
--- /dev/null
+++ b/spec/features/projects/user_deletes_files_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe 'User deletes files' do
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository, name: 'Shop') }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when an user has write access' do
+ before do
+ project.team << [user, :master]
+ visit(project_tree_path_root_ref)
+ end
+
+ it 'deletes the file', js: true do
+ click_link('.gitignore')
+
+ expect(page).to have_content('.gitignore')
+
+ click_on('Delete')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Delete file')
+
+ expect(current_path).to eq(project_tree_path(project, 'master'))
+ expect(page).not_to have_content('.gitignore')
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'deletes the file in a forked project', js: true do
+ click_link('.gitignore')
+
+ expect(page).to have_content('.gitignore')
+
+ click_on('Delete')
+
+ expect(page).to have_link('Fork')
+ expect(page).to have_button('Cancel')
+
+ click_link('Fork')
+
+ expect(page).to have_content(fork_message)
+
+ click_on('Delete')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Delete file')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+ expect(page).to have_content('New commit message')
+ end
+ end
+end
diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb
new file mode 100644
index 00000000000..8ae89c980b9
--- /dev/null
+++ b/spec/features/projects/user_edits_files_spec.rb
@@ -0,0 +1,122 @@
+require 'spec_helper'
+
+describe 'User edits files' do
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository, name: 'Shop') }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when an user has write access' do
+ before do
+ project.team << [user, :master]
+ visit(project_tree_path_root_ref)
+ end
+
+ it 'inserts a content of a file', js: true do
+ click_link('.gitignore')
+ find('.js-edit-blob').click
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+
+ expect(evaluate_script('ace.edit("editor").getValue()')).to eq('*.rbca')
+ end
+
+ it 'does not show the edit link if a file is binary' do
+ binary_file = File.join(project.repository.root_ref, 'files/images/logo-black.png')
+ visit(project_blob_path(project, binary_file))
+
+ expect(page).not_to have_link('edit')
+ end
+
+ it 'commits an edited file', js: true do
+ click_link('.gitignore')
+ find('.js-edit-blob').click
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ expect(current_path).to eq(project_blob_path(project, 'master/.gitignore'))
+
+ wait_for_requests
+
+ expect(page).to have_content('*.rbca')
+ end
+
+ it 'commits an edited file to a new branch', js: true do
+ click_link('.gitignore')
+ find('.js-edit-blob').click
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ fill_in(:branch_name, with: 'new_branch_name', visible: true)
+ click_button('Commit changes')
+
+ expect(current_path).to eq(project_new_merge_request_path(project))
+
+ click_link('Changes')
+
+ wait_for_requests
+ expect(page).to have_content('*.rbca')
+ end
+
+ it 'shows the diff of an edited file', js: true do
+ click_link('.gitignore')
+ find('.js-edit-blob').click
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ click_link('Preview changes')
+
+ expect(page).to have_css('.line_holder.new')
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'inserts a content of a file in a forked project', js: true do
+ click_link('.gitignore')
+ find('.js-edit-blob').click
+
+ expect(page).to have_link('Fork')
+ expect(page).to have_button('Cancel')
+
+ click_link('Fork')
+
+ expect(page).to have_content(fork_message)
+
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+
+ expect(evaluate_script('ace.edit("editor").getValue()')).to eq('*.rbca')
+ end
+
+ it 'commits an edited file in a forked project', js: true do
+ click_link('.gitignore')
+ find('.js-edit-blob').click
+
+ expect(page).to have_link('Fork')
+ expect(page).to have_button('Cancel')
+
+ click_link('Fork')
+ execute_script("ace.edit('editor').setValue('*.rbca')")
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+
+ wait_for_requests
+
+ expect(page).to have_content('New commit message')
+ end
+ end
+end
diff --git a/spec/features/projects/user_replaces_files_spec.rb b/spec/features/projects/user_replaces_files_spec.rb
new file mode 100644
index 00000000000..e284fdefd4f
--- /dev/null
+++ b/spec/features/projects/user_replaces_files_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+describe 'User replaces files' do
+ include DropzoneHelper
+
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository, name: 'Shop') }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when an user has write access' do
+ before do
+ project.team << [user, :master]
+ visit(project_tree_path_root_ref)
+ end
+
+ it 'replaces an existed file with a new one', js: true do
+ click_link('.gitignore')
+
+ expect(page).to have_content('.gitignore')
+
+ click_on('Replace')
+ drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
+
+ page.within('#modal-upload-blob') do
+ fill_in(:commit_message, with: 'Replacement file commit message')
+ end
+
+ click_button('Replace file')
+
+ expect(page).to have_content('Lorem ipsum dolor sit amet')
+ expect(page).to have_content('Sed ut perspiciatis unde omnis')
+ expect(page).to have_content('Replacement file commit message')
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'replaces an existed file with a new one in a forked project', js: true do
+ click_link('.gitignore')
+
+ expect(page).to have_content('.gitignore')
+
+ click_on('Replace')
+
+ expect(page).to have_link('Fork')
+ expect(page).to have_button('Cancel')
+
+ click_link('Fork')
+
+ expect(page).to have_content(fork_message)
+
+ click_on('Replace')
+ drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
+
+ page.within('#modal-upload-blob') do
+ fill_in(:commit_message, with: 'Replacement file commit message')
+ end
+
+ click_button('Replace file')
+
+ expect(page).to have_content('Replacement file commit message')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+
+ click_link('Changes')
+
+ expect(page).to have_content('Lorem ipsum dolor sit amet')
+ expect(page).to have_content('Sed ut perspiciatis unde omnis')
+ end
+ end
+end
diff --git a/spec/features/projects/user_uploads_files_spec.rb b/spec/features/projects/user_uploads_files_spec.rb
new file mode 100644
index 00000000000..98871317ca3
--- /dev/null
+++ b/spec/features/projects/user_uploads_files_spec.rb
@@ -0,0 +1,82 @@
+require 'spec_helper'
+
+describe 'User uploads files' do
+ include DropzoneHelper
+
+ let(:fork_message) do
+ "You're not allowed to make changes to this project directly. "\
+ "A fork of this project has been created that you can make changes in, so you can submit a merge request."
+ end
+ let(:project) { create(:project, :repository, name: 'Shop') }
+ let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
+ let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
+ let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ sign_in(user)
+ end
+
+ context 'when an user has write access' do
+ before do
+ visit(project_tree_path_root_ref)
+ end
+
+ it 'uploads and commit a new file', js: true do
+ find('.add-to-tree').click
+ click_link('Upload file')
+ drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
+
+ page.within('#modal-upload-blob') do
+ fill_in(:commit_message, with: 'New commit message')
+ end
+
+ fill_in(:branch_name, with: 'new_branch_name', visible: true)
+ click_button('Upload file')
+
+ expect(page).to have_content('New commit message')
+ expect(current_path).to eq(project_new_merge_request_path(project))
+
+ click_link('Changes')
+
+ expect(page).to have_content('Lorem ipsum dolor sit amet')
+ expect(page).to have_content('Sed ut perspiciatis unde omnis')
+ end
+ end
+
+ context 'when an user does not have write access' do
+ before do
+ project2.team << [user, :reporter]
+ visit(project2_tree_path_root_ref)
+ end
+
+ it 'uploads and commit a new fileto a forked project', js: true do
+ find('.add-to-tree').click
+ click_link('Upload file')
+
+ expect(page).to have_content(fork_message)
+
+ find('.add-to-tree').click
+ click_link('Upload file')
+ drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
+
+ page.within('#modal-upload-blob') do
+ fill_in(:commit_message, with: 'New commit message')
+ end
+
+ click_button('Upload file')
+
+ expect(page).to have_content('New commit message')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+
+ click_link('Changes')
+
+ expect(page).to have_content('Lorem ipsum dolor sit amet')
+ expect(page).to have_content('Sed ut perspiciatis unde omnis')
+ end
+ end
+end
diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb
index f6a640b90b4..2a316a0d0db 100644
--- a/spec/features/projects/view_on_env_spec.rb
+++ b/spec/features/projects/view_on_env_spec.rb
@@ -50,9 +50,9 @@ describe 'View on environment', js: true do
let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: branch_name) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit diffs_project_merge_request_path(project, merge_request)
wait_for_requests
end
@@ -66,9 +66,9 @@ describe 'View on environment', js: true do
context 'when visiting a comparison for the branch' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_compare_path(project.namespace, project, from: 'master', to: branch_name)
+ visit project_compare_path(project, from: 'master', to: branch_name)
wait_for_requests
end
@@ -80,9 +80,9 @@ describe 'View on environment', js: true do
context 'when visiting a comparison for the commit' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_compare_path(project.namespace, project, from: 'master', to: sha)
+ visit project_compare_path(project, from: 'master', to: sha)
wait_for_requests
end
@@ -94,9 +94,9 @@ describe 'View on environment', js: true do
context 'when visiting a blob on the branch' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_blob_path(project.namespace, project, File.join(branch_name, file_path))
+ visit project_blob_path(project, File.join(branch_name, file_path))
wait_for_requests
end
@@ -108,9 +108,9 @@ describe 'View on environment', js: true do
context 'when visiting a blob on the commit' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_blob_path(project.namespace, project, File.join(sha, file_path))
+ visit project_blob_path(project, File.join(sha, file_path))
wait_for_requests
end
@@ -122,9 +122,9 @@ describe 'View on environment', js: true do
context 'when visiting the commit' do
before do
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_commit_path(project.namespace, project, sha)
+ visit project_commit_path(project, sha)
wait_for_requests
end
diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb
index 7be54dec590..327bda28dd6 100644
--- a/spec/features/projects/wiki/markdown_preview_spec.rb
+++ b/spec/features/projects/wiki/markdown_preview_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Projects > Wiki > User previews markdown changes', feature: true, js: true do
+feature 'Projects > Wiki > User previews markdown changes', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
let(:wiki_content) do
<<-HEREDOC
[regular link](regular)
@@ -16,9 +16,9 @@ feature 'Projects > Wiki > User previews markdown changes', feature: true, js: t
project.team << [user, :master]
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
find('.shortcuts-wiki').click
end
diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb
index ab0ed9b8204..2c668185666 100644
--- a/spec/features/projects/wiki/shortcuts_spec.rb
+++ b/spec/features/projects/wiki/shortcuts_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Wiki shortcuts', :feature, :js do
+feature 'Wiki shortcuts', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace) }
let(:wiki_page) do
@@ -8,8 +8,8 @@ feature 'Wiki shortcuts', :feature, :js do
end
before do
- gitlab_sign_in(user)
- visit namespace_project_wiki_path(project.namespace, project, wiki_page)
+ sign_in(user)
+ visit project_wiki_path(project, wiki_page)
end
scenario 'Visit edit wiki page using "e" keyboard shortcut' do
diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
index 192fd597b78..78c619f6301 100644
--- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
@@ -1,20 +1,23 @@
require 'spec_helper'
-feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
+feature 'Projects > Wiki > User creates wiki page', :js do
let(:user) { create(:user) }
background do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_path(project.namespace, project)
- find('.shortcuts-wiki').click
+ visit project_path(project)
end
context 'in the user namespace' do
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
context 'when wiki is empty' do
+ before do
+ find('.shortcuts-wiki').trigger('click')
+ end
+
scenario 'commit message field has value "Create home"' do
expect(page).to have_field('wiki[message]', with: 'Create home')
end
@@ -67,10 +70,11 @@ feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
context 'when wiki is not empty' do
before do
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
+ find('.shortcuts-wiki').trigger('click')
end
context 'via the "new wiki page" page' do
- scenario 'when the wiki page has a single word name', js: true do
+ scenario 'when the wiki page has a single word name' do
click_link 'New page'
page.within '#modal-new-wiki' do
@@ -91,7 +95,7 @@ feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
expect(page).to have_content('My awesome wiki!')
end
- scenario 'when the wiki page has spaces in the name', js: true do
+ scenario 'when the wiki page has spaces in the name' do
click_link 'New page'
page.within '#modal-new-wiki' do
@@ -112,7 +116,7 @@ feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
expect(page).to have_content('My awesome wiki!')
end
- scenario 'when the wiki page has hyphens in the name', js: true do
+ scenario 'when the wiki page has hyphens in the name' do
click_link 'New page'
page.within '#modal-new-wiki' do
@@ -134,7 +138,7 @@ feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
end
end
- scenario 'content has autocomplete', :js do
+ scenario 'content has autocomplete' do
click_link 'New page'
page.within '#modal-new-wiki' do
@@ -153,9 +157,13 @@ feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
end
context 'in a group namespace' do
- let(:project) { create(:project, namespace: create(:group, :public)) }
+ let(:project) { create(:empty_project, namespace: create(:group, :public)) }
context 'when wiki is empty' do
+ before do
+ find('.shortcuts-wiki').trigger('click')
+ end
+
scenario 'commit message field has value "Create home"' do
expect(page).to have_field('wiki[message]', with: 'Create home')
end
@@ -175,9 +183,10 @@ feature 'Projects > Wiki > User creates wiki page', js: true, feature: true do
context 'when wiki is not empty' do
before do
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
+ find('.shortcuts-wiki').trigger('click')
end
- scenario 'via the "new wiki page" page', js: true do
+ scenario 'via the "new wiki page" page' do
click_link 'New page'
page.within '#modal-new-wiki' do
diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
index 7d31122af35..9c58e336605 100644
--- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe 'Projects > Wiki > User views Git access wiki page', :feature do
+describe 'Projects > Wiki > User views Git access wiki page' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:wiki_page) do
WikiPages::CreateService.new(
project,
@@ -13,11 +13,11 @@ describe 'Projects > Wiki > User views Git access wiki page', :feature do
end
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
scenario 'Visit Wiki Page Current Commit' do
- visit namespace_project_wiki_path(project.namespace, project, wiki_page)
+ visit project_wiki_path(project, wiki_page)
click_link 'Clone repository'
expect(page).to have_text("Clone repository #{project.wiki.path_with_namespace}")
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
index 64a30438681..8271428582d 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
-feature 'Projects > Wiki > User updates wiki page', feature: true do
+feature 'Projects > Wiki > User updates wiki page' do
let(:user) { create(:user) }
+ let!(:wiki_page) { WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute }
background do
project.team << [user, :master]
- WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_wikis_path(project.namespace, project)
+ visit project_wikis_path(project)
end
context 'in the user namespace' do
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
context 'the home page' do
scenario 'success when the wiki content is not empty' do
@@ -51,10 +51,20 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do
expect(page).to have_selector('.atwho-view')
end
end
+
+ scenario 'page has been updated since the user opened the edit page' do
+ click_link 'Edit'
+
+ wiki_page.update('Update')
+
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Someone edited the page the same time you did.'
+ end
end
context 'in a group namespace' do
- let(:project) { create(:project, namespace: create(:group, :public)) }
+ let(:project) { create(:empty_project, namespace: create(:group, :public)) }
scenario 'the home page' do
click_link 'Edit'
diff --git a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb
index 8a88ab247f3..4f94ab1a609 100644
--- a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-feature 'Projects > Wiki > User views the wiki page', feature: true do
+feature 'Projects > Wiki > User views the wiki page' do
let(:user) { create(:user) }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:old_page_version_id) { wiki_page.versions.last.id }
let(:wiki_page) do
WikiPages::CreateService.new(
@@ -15,7 +15,7 @@ feature 'Projects > Wiki > User views the wiki page', feature: true do
background do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
WikiPages::UpdateService.new(
project,
user,
@@ -26,18 +26,13 @@ feature 'Projects > Wiki > User views the wiki page', feature: true do
end
scenario 'Visit Wiki Page Current Commit' do
- visit namespace_project_wiki_path(project.namespace, project, wiki_page)
+ visit project_wiki_path(project, wiki_page)
expect(page).to have_selector('a.btn', text: 'Edit')
end
scenario 'Visit Wiki Page Historical Commit' do
- visit namespace_project_wiki_path(
- project.namespace,
- project,
- wiki_page,
- version_id: old_page_version_id
- )
+ visit project_wiki_path(project, wiki_page, version_id: old_page_version_id)
expect(page).not_to have_selector('a.btn', text: 'Edit')
end
diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb
index 36799925167..8d1e6f66039 100644
--- a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe 'Projects > Wiki > User views wiki in project page', feature: true do
+describe 'Projects > Wiki > User views wiki in project page' do
let(:user) { create(:user) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when repository is disabled for project' do
@@ -27,14 +27,10 @@ describe 'Projects > Wiki > User views wiki in project page', feature: true do
end
it 'displays the correct URL for the link' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
expect(page).to have_link(
'some link',
- href: namespace_project_wiki_path(
- project.namespace,
- project,
- 'other-page'
- )
+ href: project_wiki_path(project, 'other-page')
)
end
end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 7e8a703db93..3295f7f9174 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-feature 'Project', feature: true do
+feature 'Project' do
describe 'description' do
let(:project) { create(:project, :repository) }
- let(:path) { namespace_project_path(project.namespace, project) }
+ let(:path) { project_path(project) }
before do
- gitlab_sign_in(:admin)
+ sign_in(create(:admin))
end
it 'parses Markdown' do
@@ -39,9 +39,9 @@ feature 'Project', feature: true do
let(:project) { create(:empty_project, namespace: user.namespace) }
before do
- gitlab_sign_in user
+ sign_in user
create(:forked_project_link, forked_to_project: project)
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
end
it 'removes fork' do
@@ -60,9 +60,9 @@ feature 'Project', feature: true do
let(:project) { create(:empty_project, namespace: user.namespace, name: 'project1') }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :master]
- visit edit_namespace_project_path(project.namespace, project)
+ visit edit_project_path(project)
end
it 'removes a project' do
@@ -79,9 +79,9 @@ feature 'Project', feature: true do
let(:project) { create(:empty_project, namespace: user.namespace) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.add_user(user, Gitlab::Access::MASTER)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
it 'clicks toggle and shows dropdown', js: true do
@@ -98,10 +98,10 @@ feature 'Project', feature: true do
context 'on issues page', js: true do
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.add_user(user, Gitlab::Access::MASTER)
project2.add_user(user, Gitlab::Access::MASTER)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it 'clicks toggle and shows dropdown' do
@@ -123,8 +123,8 @@ feature 'Project', feature: true do
before do
project.team << [user, :master]
- gitlab_sign_in user
- visit namespace_project_path(project.namespace, project)
+ sign_in user
+ visit project_path(project)
end
it 'has working links to files' do
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index 5778b5271f2..03e43fce384 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Protected Branches', feature: true, js: true do
+feature 'Protected Branches', js: true do
let(:user) { create(:user, :admin) }
let(:project) { create(:project, :repository) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
def set_protected_branch_name(branch_name)
@@ -16,7 +16,7 @@ feature 'Protected Branches', feature: true, js: true do
describe "explicit protected branches" do
it "allows creating explicit protected branches" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('some-branch')
click_on "Protect"
@@ -29,7 +29,7 @@ feature 'Protected Branches', feature: true, js: true do
commit = create(:commit, project: project)
project.repository.add_branch(user, 'some-branch', commit.id)
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('some-branch')
click_on "Protect"
@@ -37,7 +37,7 @@ feature 'Protected Branches', feature: true, js: true do
end
it "displays an error message if the named branch does not exist" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('some-branch')
click_on "Protect"
@@ -47,7 +47,7 @@ feature 'Protected Branches', feature: true, js: true do
describe "wildcard protected branches" do
it "allows creating protected branches with a wildcard" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('*-stable')
click_on "Protect"
@@ -60,7 +60,7 @@ feature 'Protected Branches', feature: true, js: true do
project.repository.add_branch(user, 'production-stable', 'master')
project.repository.add_branch(user, 'staging-stable', 'master')
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('*-stable')
click_on "Protect"
@@ -72,11 +72,11 @@ feature 'Protected Branches', feature: true, js: true do
project.repository.add_branch(user, 'staging-stable', 'master')
project.repository.add_branch(user, 'development', 'master')
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('*-stable')
click_on "Protect"
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
click_on "2 matching branches"
within(".protected-branches-list") do
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index 73a80692154..c9ba1a8c088 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-feature 'Projected Tags', feature: true, js: true do
+feature 'Projected Tags', js: true do
let(:user) { create(:user, :admin) }
let(:project) { create(:project, :repository) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
def set_protected_tag_name(tag_name)
@@ -17,7 +17,7 @@ feature 'Projected Tags', feature: true, js: true do
describe "explicit protected tags" do
it "allows creating explicit protected tags" do
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
click_on "Protect"
@@ -30,7 +30,7 @@ feature 'Projected Tags', feature: true, js: true do
commit = create(:commit, project: project)
project.repository.add_tag(user, 'some-tag', commit.id)
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
click_on "Protect"
@@ -38,7 +38,7 @@ feature 'Projected Tags', feature: true, js: true do
end
it "displays an error message if the named tag does not exist" do
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('some-tag')
click_on "Protect"
@@ -48,7 +48,7 @@ feature 'Projected Tags', feature: true, js: true do
describe "wildcard protected tags" do
it "allows creating protected tags with a wildcard" do
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
click_on "Protect"
@@ -61,7 +61,7 @@ feature 'Projected Tags', feature: true, js: true do
project.repository.add_tag(user, 'production-stable', 'master')
project.repository.add_tag(user, 'staging-stable', 'master')
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
click_on "Protect"
@@ -73,11 +73,11 @@ feature 'Projected Tags', feature: true, js: true do
project.repository.add_tag(user, 'staging-stable', 'master')
project.repository.add_tag(user, 'development', 'master')
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('*-stable')
click_on "Protect"
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
click_on "2 matching tags"
within(".protected-tags-list") do
diff --git a/spec/features/raven_js_spec.rb b/spec/features/raven_js_spec.rb
index e8fa49c18cb..b1f51959d54 100644
--- a/spec/features/raven_js_spec.rb
+++ b/spec/features/raven_js_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'RavenJS', :feature, :js do
+feature 'RavenJS', :js do
let(:raven_path) { '/raven.bundle.js' }
it 'should not load raven if sentry is disabled' do
diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb
index 12049822753..1074eb62b33 100644
--- a/spec/features/reportable_note/commit_spec.rb
+++ b/spec/features/reportable_note/commit_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Reportable note on commit', :feature, :js do
+describe 'Reportable note on commit', :js do
include RepoHelpers
let(:user) { create(:user) }
@@ -8,14 +8,14 @@ describe 'Reportable note on commit', :feature, :js do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'a normal note' do
let!(:note) { create(:note_on_commit, commit_id: sample_commit.id, project: project) }
before do
- visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
+ visit project_commit_path(project, sample_commit.id)
end
it_behaves_like 'reportable note'
@@ -25,7 +25,7 @@ describe 'Reportable note on commit', :feature, :js do
let!(:note) { create(:diff_note_on_commit, commit_id: sample_commit.id, project: project) }
before do
- visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
+ visit project_commit_path(project, sample_commit.id)
end
it_behaves_like 'reportable note'
diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb
index ca2a7f41496..9964a32db2e 100644
--- a/spec/features/reportable_note/issue_spec.rb
+++ b/spec/features/reportable_note/issue_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Reportable note on issue', :feature, :js do
+describe 'Reportable note on issue', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
@@ -8,9 +8,9 @@ describe 'Reportable note on issue', :feature, :js do
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
it_behaves_like 'reportable note'
diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb
index 8e75b4af3eb..a491abdb6cb 100644
--- a/spec/features/reportable_note/merge_request_spec.rb
+++ b/spec/features/reportable_note/merge_request_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper'
-describe 'Reportable note on merge request', :feature, :js do
+describe 'Reportable note on merge request', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit project_merge_request_path(project, merge_request)
end
context 'a normal note' do
diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb
index 5bee4a31379..9a14024684c 100644
--- a/spec/features/reportable_note/snippets_spec.rb
+++ b/spec/features/reportable_note/snippets_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe 'Reportable note on snippets', :feature, :js do
+describe 'Reportable note on snippets', :js do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
before do
project.add_master(user)
- gitlab_sign_in(user)
+ sign_in(user)
end
describe 'on project snippet' do
@@ -14,7 +14,7 @@ describe 'Reportable note on snippets', :feature, :js do
let!(:note) { create(:note_on_project_snippet, noteable: snippet, project: project) }
before do
- visit namespace_project_snippet_path(project.namespace, project, snippet)
+ visit project_snippet_path(project, snippet)
end
it_behaves_like 'reportable note'
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index ea18879b4bf..1725b70acf3 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -1,12 +1,10 @@
require 'spec_helper'
describe "Runners" do
- include GitlabRoutingHelper
-
let(:user) { create(:user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
end
describe "specific runners" do
@@ -124,7 +122,7 @@ describe "Runners" do
end
scenario 'user checks default configuration' do
- visit namespace_project_runner_path(project.namespace, project, runner)
+ visit project_runner_path(project, runner)
expect(page).to have_content 'Can run untagged jobs Yes'
end
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index db947c32731..20dcb640c9c 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Search", feature: true do
+describe "Search" do
include FilteredSearchHelpers
let(:user) { create(:user) }
@@ -9,7 +9,7 @@ describe "Search", feature: true do
let!(:issue2) { create(:issue, project: project, author: user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :reporter]
visit search_path
end
@@ -88,7 +88,7 @@ describe "Search", feature: true do
end
it 'finds comment' do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
page.within '.search' do
fill_in 'search', with: note.note
@@ -111,7 +111,7 @@ describe "Search", feature: true do
project: project)
# Must visit project dashboard since global search won't search
# everything (e.g. comments, snippets, etc.)
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
page.within '.search' do
fill_in 'search', with: note.note
@@ -125,7 +125,7 @@ describe "Search", feature: true do
it 'finds a commit' do
project = create(:project, :repository) { |p| p.add_reporter(user) }
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
page.within '.search' do
fill_in 'search', with: 'add'
@@ -139,7 +139,7 @@ describe "Search", feature: true do
it 'finds a code' do
project = create(:project, :repository) { |p| p.add_reporter(user) }
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
page.within '.search' do
fill_in 'search', with: 'application.js'
@@ -154,9 +154,9 @@ describe "Search", feature: true do
end
end
- describe 'Right header search field', feature: true do
+ describe 'Right header search field' do
it 'allows enter key to search', js: true do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
fill_in 'search', with: 'gitlab'
find('#search').native.send_keys(:enter)
@@ -167,7 +167,7 @@ describe "Search", feature: true do
describe 'Search in project page' do
before do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
end
it 'shows top right search form' do
@@ -256,7 +256,7 @@ describe "Search", feature: true do
click_button 'Search'
- expect(page).to have_current_path(namespace_project_commit_path(project.namespace, project, '6d394385cf567f80a8fd85055db1ab4c5295806f'))
+ expect(page).to have_current_path(project_commit_path(project, '6d394385cf567f80a8fd85055db1ab4c5295806f'))
end
it 'redirects to single commit regardless of query case' do
@@ -264,7 +264,7 @@ describe "Search", feature: true do
click_button 'Search'
- expect(page).to have_current_path(namespace_project_commit_path(project.namespace, project, '6d394385cf567f80a8fd85055db1ab4c5295806f'))
+ expect(page).to have_current_path(project_commit_path(project, '6d394385cf567f80a8fd85055db1ab4c5295806f'))
end
it 'holds on /search page when the only commit is found by message' do
diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb
index e180ca53eb5..3ca1303bda6 100644
--- a/spec/features/security/admin_access_spec.rb
+++ b/spec/features/security/admin_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Admin::Projects", feature: true do
+describe "Admin::Projects" do
include AccessMatchers
describe "GET /admin/projects" do
diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb
index 40f773956d1..149bd32e736 100644
--- a/spec/features/security/dashboard_access_spec.rb
+++ b/spec/features/security/dashboard_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Dashboard access", feature: true do
+describe "Dashboard access" do
include AccessMatchers
describe "GET /dashboard" do
diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb
index 87cce32d6c6..bf7be33013e 100644
--- a/spec/features/security/group/internal_access_spec.rb
+++ b/spec/features/security/group/internal_access_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-describe 'Internal Group access', feature: true do
+describe 'Internal Group access' do
include AccessMatchers
let(:group) { create(:group, :internal) }
- let(:project) { create(:project, :internal, group: group) }
+ let(:project) { create(:empty_project, :internal, group: group) }
let(:project_guest) do
create(:user) do |user|
project.add_guest(user)
@@ -49,6 +49,7 @@ describe 'Internal Group access', feature: true do
end
describe 'GET /groups/:path/merge_requests' do
+ let(:project) { create(:project, :internal, :repository, group: group) }
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for(:admin) }
diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb
index 1d6b3e77c22..c399d7a0851 100644
--- a/spec/features/security/group/private_access_spec.rb
+++ b/spec/features/security/group/private_access_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-describe 'Private Group access', feature: true do
+describe 'Private Group access' do
include AccessMatchers
let(:group) { create(:group, :private) }
- let(:project) { create(:project, :private, group: group) }
+ let(:project) { create(:empty_project, :private, group: group) }
let(:project_guest) do
create(:user) do |user|
project.add_guest(user)
@@ -49,6 +49,7 @@ describe 'Private Group access', feature: true do
end
describe 'GET /groups/:path/merge_requests' do
+ let(:project) { create(:project, :private, :repository, group: group) }
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for(:admin) }
diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb
index d7d76177269..63e4d7ca65c 100644
--- a/spec/features/security/group/public_access_spec.rb
+++ b/spec/features/security/group/public_access_spec.rb
@@ -1,10 +1,10 @@
require 'rails_helper'
-describe 'Public Group access', feature: true do
+describe 'Public Group access' do
include AccessMatchers
let(:group) { create(:group, :public) }
- let(:project) { create(:project, :public, group: group) }
+ let(:project) { create(:empty_project, :public, group: group) }
let(:project_guest) do
create(:user) do |user|
project.add_guest(user)
@@ -49,6 +49,7 @@ describe 'Public Group access', feature: true do
end
describe 'GET /groups/:path/merge_requests' do
+ let(:project) { create(:project, :public, :repository, group: group) }
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for(:admin) }
diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb
index c19678ab381..41eb7b26578 100644
--- a/spec/features/security/profile_access_spec.rb
+++ b/spec/features/security/profile_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Profile access", feature: true do
+describe "Profile access" do
include AccessMatchers
describe "GET /profile/keys" do
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index f33406a40a7..a7928857b7d 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe "Internal Project Access", feature: true do
+describe "Internal Project Access" do
include AccessMatchers
- set(:project) { create(:project, :internal) }
+ set(:project) { create(:project, :internal, :repository) }
describe "Project should be internal" do
describe '#internal?' do
@@ -13,7 +13,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path" do
- subject { namespace_project_path(project.namespace, project) }
+ subject { project_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -27,7 +27,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/tree/master" do
- subject { namespace_project_tree_path(project.namespace, project, project.repository.root_ref) }
+ subject { project_tree_path(project, project.repository.root_ref) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -41,7 +41,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/commits/master" do
- subject { namespace_project_commits_path(project.namespace, project, project.repository.root_ref, limit: 1) }
+ subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -55,7 +55,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/commit/:sha" do
- subject { namespace_project_commit_path(project.namespace, project, project.repository.commit) }
+ subject { project_commit_path(project, project.repository.commit) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -69,7 +69,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/compare" do
- subject { namespace_project_compare_index_path(project.namespace, project) }
+ subject { project_compare_index_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -83,7 +83,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/settings/members" do
- subject { namespace_project_settings_members_path(project.namespace, project) }
+ subject { project_settings_members_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -97,7 +97,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/settings/ci_cd" do
- subject { namespace_project_settings_ci_cd_path(project.namespace, project) }
+ subject { project_settings_ci_cd_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -111,7 +111,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/settings/repository" do
- subject { namespace_project_settings_repository_path(project.namespace, project) }
+ subject { project_settings_repository_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -126,7 +126,7 @@ describe "Internal Project Access", feature: true do
describe "GET /:project_path/blob" do
let(:commit) { project.repository.commit }
- subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore')) }
+ subject { project_blob_path(project, File.join(commit.id, '.gitignore')) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -140,7 +140,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/edit" do
- subject { edit_namespace_project_path(project.namespace, project) }
+ subject { edit_project_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -154,7 +154,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/deploy_keys" do
- subject { namespace_project_deploy_keys_path(project.namespace, project) }
+ subject { project_deploy_keys_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -168,7 +168,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/issues" do
- subject { namespace_project_issues_path(project.namespace, project) }
+ subject { project_issues_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -183,7 +183,7 @@ describe "Internal Project Access", feature: true do
describe "GET /:project_path/issues/:id/edit" do
let(:issue) { create(:issue, project: project) }
- subject { edit_namespace_project_issue_path(project.namespace, project, issue) }
+ subject { edit_project_issue_path(project, issue) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -197,7 +197,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/snippets" do
- subject { namespace_project_snippets_path(project.namespace, project) }
+ subject { project_snippets_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -211,7 +211,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/snippets/new" do
- subject { new_namespace_project_snippet_path(project.namespace, project) }
+ subject { new_project_snippet_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -225,7 +225,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/merge_requests" do
- subject { namespace_project_merge_requests_path(project.namespace, project) }
+ subject { project_merge_requests_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -239,7 +239,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/merge_requests/new" do
- subject { new_namespace_project_merge_request_path(project.namespace, project) }
+ subject { project_new_merge_request_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -253,7 +253,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/branches" do
- subject { namespace_project_branches_path(project.namespace, project) }
+ subject { project_branches_path(project) }
before do
# Speed increase
@@ -272,7 +272,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/tags" do
- subject { namespace_project_tags_path(project.namespace, project) }
+ subject { project_tags_path(project) }
before do
# Speed increase
@@ -291,7 +291,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/settings/integrations" do
- subject { namespace_project_settings_integrations_path(project.namespace, project) }
+ subject { project_settings_integrations_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -305,7 +305,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/pipelines" do
- subject { namespace_project_pipelines_path(project.namespace, project) }
+ subject { project_pipelines_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -320,7 +320,7 @@ describe "Internal Project Access", feature: true do
describe "GET /:project_path/pipelines/:id" do
let(:pipeline) { create(:ci_pipeline, project: project) }
- subject { namespace_project_pipeline_path(project.namespace, project, pipeline) }
+ subject { project_pipeline_path(project, pipeline) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -334,7 +334,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/builds" do
- subject { namespace_project_jobs_path(project.namespace, project) }
+ subject { project_jobs_path(project) }
context "when allowed for public and internal" do
before do
@@ -372,7 +372,7 @@ describe "Internal Project Access", feature: true do
describe "GET /:project_path/builds/:id" do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- subject { namespace_project_job_path(project.namespace, project, build.id) }
+ subject { project_job_path(project, build.id) }
context "when allowed for public and internal" do
before do
@@ -410,7 +410,7 @@ describe "Internal Project Access", feature: true do
describe 'GET /:project_path/builds/:id/trace' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- subject { trace_namespace_project_job_path(project.namespace, project, build.id) }
+ subject { trace_project_job_path(project, build.id) }
context 'when allowed for public and internal' do
before do
@@ -446,7 +446,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/pipeline_schedules" do
- subject { namespace_project_pipeline_schedules_path(project.namespace, project) }
+ subject { project_pipeline_schedules_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -460,7 +460,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/environments" do
- subject { namespace_project_environments_path(project.namespace, project) }
+ subject { project_environments_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -475,7 +475,7 @@ describe "Internal Project Access", feature: true do
describe "GET /:project_path/environments/:id" do
let(:environment) { create(:environment, project: project) }
- subject { namespace_project_environment_path(project.namespace, project, environment) }
+ subject { project_environment_path(project, environment) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -490,7 +490,7 @@ describe "Internal Project Access", feature: true do
describe "GET /:project_path/environments/:id/deployments" do
let(:environment) { create(:environment, project: project) }
- subject { namespace_project_environment_deployments_path(project.namespace, project, environment) }
+ subject { project_environment_deployments_path(project, environment) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -504,7 +504,7 @@ describe "Internal Project Access", feature: true do
end
describe "GET /:project_path/environments/new" do
- subject { new_namespace_project_environment_path(project.namespace, project) }
+ subject { new_project_environment_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -526,7 +526,7 @@ describe "Internal Project Access", feature: true do
project.container_repositories << container_repository
end
- subject { namespace_project_container_registry_index_path(project.namespace, project) }
+ subject { project_container_registry_index_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index b676c236758..a4396b20afd 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe "Private Project Access", feature: true do
+describe "Private Project Access" do
include AccessMatchers
- set(:project) { create(:project, :private, public_builds: false) }
+ set(:project) { create(:project, :private, :repository, public_builds: false) }
describe "Project should be private" do
describe '#private?' do
@@ -13,7 +13,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path" do
- subject { namespace_project_path(project.namespace, project) }
+ subject { project_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -27,7 +27,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/tree/master" do
- subject { namespace_project_tree_path(project.namespace, project, project.repository.root_ref) }
+ subject { project_tree_path(project, project.repository.root_ref) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -41,7 +41,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/commits/master" do
- subject { namespace_project_commits_path(project.namespace, project, project.repository.root_ref, limit: 1) }
+ subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -55,7 +55,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/commit/:sha" do
- subject { namespace_project_commit_path(project.namespace, project, project.repository.commit) }
+ subject { project_commit_path(project, project.repository.commit) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -69,7 +69,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/compare" do
- subject { namespace_project_compare_index_path(project.namespace, project) }
+ subject { project_compare_index_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -83,7 +83,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/settings/members" do
- subject { namespace_project_settings_members_path(project.namespace, project) }
+ subject { project_settings_members_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -97,7 +97,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/settings/ci_cd" do
- subject { namespace_project_settings_ci_cd_path(project.namespace, project) }
+ subject { project_settings_ci_cd_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -111,7 +111,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/settings/repository" do
- subject { namespace_project_settings_repository_path(project.namespace, project) }
+ subject { project_settings_repository_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -126,7 +126,7 @@ describe "Private Project Access", feature: true do
describe "GET /:project_path/blob" do
let(:commit) { project.repository.commit }
- subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore'))}
+ subject { project_blob_path(project, File.join(commit.id, '.gitignore'))}
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -140,7 +140,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/edit" do
- subject { edit_namespace_project_path(project.namespace, project) }
+ subject { edit_project_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -154,7 +154,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/deploy_keys" do
- subject { namespace_project_deploy_keys_path(project.namespace, project) }
+ subject { project_deploy_keys_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -168,7 +168,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/issues" do
- subject { namespace_project_issues_path(project.namespace, project) }
+ subject { project_issues_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -183,7 +183,7 @@ describe "Private Project Access", feature: true do
describe "GET /:project_path/issues/:id/edit" do
let(:issue) { create(:issue, project: project) }
- subject { edit_namespace_project_issue_path(project.namespace, project, issue) }
+ subject { edit_project_issue_path(project, issue) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -197,7 +197,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/snippets" do
- subject { namespace_project_snippets_path(project.namespace, project) }
+ subject { project_snippets_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -211,7 +211,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/merge_requests" do
- subject { namespace_project_merge_requests_path(project.namespace, project) }
+ subject { project_merge_requests_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -225,7 +225,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/branches" do
- subject { namespace_project_branches_path(project.namespace, project) }
+ subject { project_branches_path(project) }
before do
# Speed increase
@@ -244,7 +244,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/tags" do
- subject { namespace_project_tags_path(project.namespace, project) }
+ subject { project_tags_path(project) }
before do
# Speed increase
@@ -263,7 +263,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/namespace/hooks" do
- subject { namespace_project_settings_integrations_path(project.namespace, project) }
+ subject { project_settings_integrations_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -277,7 +277,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/pipelines" do
- subject { namespace_project_pipelines_path(project.namespace, project) }
+ subject { project_pipelines_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -304,7 +304,7 @@ describe "Private Project Access", feature: true do
describe "GET /:project_path/pipelines/:id" do
let(:pipeline) { create(:ci_pipeline, project: project) }
- subject { namespace_project_pipeline_path(project.namespace, project, pipeline) }
+ subject { project_pipeline_path(project, pipeline) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -330,7 +330,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/builds" do
- subject { namespace_project_jobs_path(project.namespace, project) }
+ subject { project_jobs_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -358,7 +358,7 @@ describe "Private Project Access", feature: true do
describe "GET /:project_path/builds/:id" do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- subject { namespace_project_job_path(project.namespace, project, build.id) }
+ subject { project_job_path(project, build.id) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -391,7 +391,7 @@ describe "Private Project Access", feature: true do
describe 'GET /:project_path/builds/:id/trace' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- subject { trace_namespace_project_job_path(project.namespace, project, build.id) }
+ subject { trace_project_job_path(project, build.id) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -421,7 +421,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/environments" do
- subject { namespace_project_environments_path(project.namespace, project) }
+ subject { project_environments_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -436,7 +436,7 @@ describe "Private Project Access", feature: true do
describe "GET /:project_path/environments/:id" do
let(:environment) { create(:environment, project: project) }
- subject { namespace_project_environment_path(project.namespace, project, environment) }
+ subject { project_environment_path(project, environment) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -451,7 +451,7 @@ describe "Private Project Access", feature: true do
describe "GET /:project_path/environments/:id/deployments" do
let(:environment) { create(:environment, project: project) }
- subject { namespace_project_environment_deployments_path(project.namespace, project, environment) }
+ subject { project_environment_deployments_path(project, environment) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -465,7 +465,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/environments/new" do
- subject { new_namespace_project_environment_path(project.namespace, project) }
+ subject { new_project_environment_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -479,7 +479,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/pipeline_schedules" do
- subject { namespace_project_pipeline_schedules_path(project.namespace, project) }
+ subject { project_pipeline_schedules_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -493,7 +493,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/pipeline_schedules/new" do
- subject { new_namespace_project_pipeline_schedule_path(project.namespace, project) }
+ subject { new_project_pipeline_schedule_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -507,7 +507,7 @@ describe "Private Project Access", feature: true do
end
describe "GET /:project_path/environments/new" do
- subject { new_namespace_project_pipeline_schedule_path(project.namespace, project) }
+ subject { new_project_pipeline_schedule_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -529,7 +529,7 @@ describe "Private Project Access", feature: true do
project.container_repositories << container_repository
end
- subject { namespace_project_container_registry_index_path(project.namespace, project) }
+ subject { project_container_registry_index_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 16a1331b2f3..fccdeb0e5b7 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe "Public Project Access", feature: true do
+describe "Public Project Access" do
include AccessMatchers
- set(:project) { create(:project, :public) }
+ set(:project) { create(:project, :public, :repository) }
describe "Project should be public" do
describe '#public?' do
@@ -13,7 +13,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path" do
- subject { namespace_project_path(project.namespace, project) }
+ subject { project_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -27,7 +27,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/tree/master" do
- subject { namespace_project_tree_path(project.namespace, project, project.repository.root_ref) }
+ subject { project_tree_path(project, project.repository.root_ref) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -41,7 +41,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/commits/master" do
- subject { namespace_project_commits_path(project.namespace, project, project.repository.root_ref, limit: 1) }
+ subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -55,7 +55,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/commit/:sha" do
- subject { namespace_project_commit_path(project.namespace, project, project.repository.commit) }
+ subject { project_commit_path(project, project.repository.commit) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -69,7 +69,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/compare" do
- subject { namespace_project_compare_index_path(project.namespace, project) }
+ subject { project_compare_index_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -83,7 +83,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/settings/members" do
- subject { namespace_project_settings_members_path(project.namespace, project) }
+ subject { project_settings_members_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -97,7 +97,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/settings/ci_cd" do
- subject { namespace_project_settings_ci_cd_path(project.namespace, project) }
+ subject { project_settings_ci_cd_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -111,7 +111,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/settings/repository" do
- subject { namespace_project_settings_repository_path(project.namespace, project) }
+ subject { project_settings_repository_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -125,7 +125,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/pipelines" do
- subject { namespace_project_pipelines_path(project.namespace, project) }
+ subject { project_pipelines_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -140,7 +140,7 @@ describe "Public Project Access", feature: true do
describe "GET /:project_path/pipelines/:id" do
let(:pipeline) { create(:ci_pipeline, project: project) }
- subject { namespace_project_pipeline_path(project.namespace, project, pipeline) }
+ subject { project_pipeline_path(project, pipeline) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -154,7 +154,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/builds" do
- subject { namespace_project_jobs_path(project.namespace, project) }
+ subject { project_jobs_path(project) }
context "when allowed for public" do
before do
@@ -192,7 +192,7 @@ describe "Public Project Access", feature: true do
describe "GET /:project_path/builds/:id" do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- subject { namespace_project_job_path(project.namespace, project, build.id) }
+ subject { project_job_path(project, build.id) }
context "when allowed for public" do
before do
@@ -230,7 +230,7 @@ describe "Public Project Access", feature: true do
describe 'GET /:project_path/builds/:id/trace' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- subject { trace_namespace_project_job_path(project.namespace, project, build.id) }
+ subject { trace_project_job_path(project, build.id) }
context 'when allowed for public' do
before do
@@ -266,7 +266,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/pipeline_schedules" do
- subject { namespace_project_pipeline_schedules_path(project.namespace, project) }
+ subject { project_pipeline_schedules_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -280,7 +280,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/environments" do
- subject { namespace_project_environments_path(project.namespace, project) }
+ subject { project_environments_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -295,7 +295,7 @@ describe "Public Project Access", feature: true do
describe "GET /:project_path/environments/:id" do
let(:environment) { create(:environment, project: project) }
- subject { namespace_project_environment_path(project.namespace, project, environment) }
+ subject { project_environment_path(project, environment) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -310,7 +310,7 @@ describe "Public Project Access", feature: true do
describe "GET /:project_path/environments/:id/deployments" do
let(:environment) { create(:environment, project: project) }
- subject { namespace_project_environment_deployments_path(project.namespace, project, environment) }
+ subject { project_environment_deployments_path(project, environment) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -324,7 +324,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/environments/new" do
- subject { new_namespace_project_environment_path(project.namespace, project) }
+ subject { new_project_environment_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -340,7 +340,7 @@ describe "Public Project Access", feature: true do
describe "GET /:project_path/blob" do
let(:commit) { project.repository.commit }
- subject { namespace_project_blob_path(project.namespace, project, File.join(commit.id, '.gitignore')) }
+ subject { project_blob_path(project, File.join(commit.id, '.gitignore')) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -353,7 +353,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/edit" do
- subject { edit_namespace_project_path(project.namespace, project) }
+ subject { edit_project_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -367,7 +367,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/deploy_keys" do
- subject { namespace_project_deploy_keys_path(project.namespace, project) }
+ subject { project_deploy_keys_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -381,7 +381,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/issues" do
- subject { namespace_project_issues_path(project.namespace, project) }
+ subject { project_issues_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -396,7 +396,7 @@ describe "Public Project Access", feature: true do
describe "GET /:project_path/issues/:id/edit" do
let(:issue) { create(:issue, project: project) }
- subject { edit_namespace_project_issue_path(project.namespace, project, issue) }
+ subject { edit_project_issue_path(project, issue) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -410,7 +410,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/snippets" do
- subject { namespace_project_snippets_path(project.namespace, project) }
+ subject { project_snippets_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -424,7 +424,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/snippets/new" do
- subject { new_namespace_project_snippet_path(project.namespace, project) }
+ subject { new_project_snippet_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -438,7 +438,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/merge_requests" do
- subject { namespace_project_merge_requests_path(project.namespace, project) }
+ subject { project_merge_requests_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -452,7 +452,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/merge_requests/new" do
- subject { new_namespace_project_merge_request_path(project.namespace, project) }
+ subject { project_new_merge_request_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -466,7 +466,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/branches" do
- subject { namespace_project_branches_path(project.namespace, project) }
+ subject { project_branches_path(project) }
before do
# Speed increase
@@ -485,7 +485,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/tags" do
- subject { namespace_project_tags_path(project.namespace, project) }
+ subject { project_tags_path(project) }
before do
# Speed increase
@@ -504,7 +504,7 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/settings/integrations" do
- subject { namespace_project_settings_integrations_path(project.namespace, project) }
+ subject { project_settings_integrations_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -526,7 +526,7 @@ describe "Public Project Access", feature: true do
project.container_repositories << container_repository
end
- subject { namespace_project_container_registry_index_path(project.namespace, project) }
+ subject { project_container_registry_index_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb
index 2659b3ee3ec..178782af56c 100644
--- a/spec/features/security/project/snippet/internal_access_spec.rb
+++ b/spec/features/security/project/snippet/internal_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Internal Project Snippets Access", feature: true do
+describe "Internal Project Snippets Access" do
include AccessMatchers
let(:project) { create(:empty_project, :internal) }
@@ -9,7 +9,7 @@ describe "Internal Project Snippets Access", feature: true do
let(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) }
describe "GET /:project_path/snippets" do
- subject { namespace_project_snippets_path(project.namespace, project) }
+ subject { project_snippets_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -23,7 +23,7 @@ describe "Internal Project Snippets Access", feature: true do
end
describe "GET /:project_path/snippets/new" do
- subject { new_namespace_project_snippet_path(project.namespace, project) }
+ subject { new_project_snippet_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -38,7 +38,7 @@ describe "Internal Project Snippets Access", feature: true do
describe "GET /:project_path/snippets/:id" do
context "for an internal snippet" do
- subject { namespace_project_snippet_path(project.namespace, project, internal_snippet) }
+ subject { project_snippet_path(project, internal_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -52,7 +52,7 @@ describe "Internal Project Snippets Access", feature: true do
end
context "for a private snippet" do
- subject { namespace_project_snippet_path(project.namespace, project, private_snippet) }
+ subject { project_snippet_path(project, private_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -68,7 +68,7 @@ describe "Internal Project Snippets Access", feature: true do
describe "GET /:project_path/snippets/:id/raw" do
context "for an internal snippet" do
- subject { raw_namespace_project_snippet_path(project.namespace, project, internal_snippet) }
+ subject { raw_project_snippet_path(project, internal_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -82,7 +82,7 @@ describe "Internal Project Snippets Access", feature: true do
end
context "for a private snippet" do
- subject { raw_namespace_project_snippet_path(project.namespace, project, private_snippet) }
+ subject { raw_project_snippet_path(project, private_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb
index 6eb9f163bd5..7725c25ca1f 100644
--- a/spec/features/security/project/snippet/private_access_spec.rb
+++ b/spec/features/security/project/snippet/private_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Private Project Snippets Access", feature: true do
+describe "Private Project Snippets Access" do
include AccessMatchers
let(:project) { create(:empty_project, :private) }
@@ -8,7 +8,7 @@ describe "Private Project Snippets Access", feature: true do
let(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) }
describe "GET /:project_path/snippets" do
- subject { namespace_project_snippets_path(project.namespace, project) }
+ subject { project_snippets_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -22,7 +22,7 @@ describe "Private Project Snippets Access", feature: true do
end
describe "GET /:project_path/snippets/new" do
- subject { new_namespace_project_snippet_path(project.namespace, project) }
+ subject { new_project_snippet_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -36,7 +36,7 @@ describe "Private Project Snippets Access", feature: true do
end
describe "GET /:project_path/snippets/:id for a private snippet" do
- subject { namespace_project_snippet_path(project.namespace, project, private_snippet) }
+ subject { project_snippet_path(project, private_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -50,7 +50,7 @@ describe "Private Project Snippets Access", feature: true do
end
describe "GET /:project_path/snippets/:id/raw for a private snippet" do
- subject { raw_namespace_project_snippet_path(project.namespace, project, private_snippet) }
+ subject { raw_project_snippet_path(project, private_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb
index f3329d0bc96..52aec75dcd0 100644
--- a/spec/features/security/project/snippet/public_access_spec.rb
+++ b/spec/features/security/project/snippet/public_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Public Project Snippets Access", feature: true do
+describe "Public Project Snippets Access" do
include AccessMatchers
let(:project) { create(:empty_project, :public) }
@@ -10,7 +10,7 @@ describe "Public Project Snippets Access", feature: true do
let(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) }
describe "GET /:project_path/snippets" do
- subject { namespace_project_snippets_path(project.namespace, project) }
+ subject { project_snippets_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -24,7 +24,7 @@ describe "Public Project Snippets Access", feature: true do
end
describe "GET /:project_path/snippets/new" do
- subject { new_namespace_project_snippet_path(project.namespace, project) }
+ subject { new_project_snippet_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -39,7 +39,7 @@ describe "Public Project Snippets Access", feature: true do
describe "GET /:project_path/snippets/:id" do
context "for a public snippet" do
- subject { namespace_project_snippet_path(project.namespace, project, public_snippet) }
+ subject { project_snippet_path(project, public_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -53,7 +53,7 @@ describe "Public Project Snippets Access", feature: true do
end
context "for an internal snippet" do
- subject { namespace_project_snippet_path(project.namespace, project, internal_snippet) }
+ subject { project_snippet_path(project, internal_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -67,7 +67,7 @@ describe "Public Project Snippets Access", feature: true do
end
context "for a private snippet" do
- subject { namespace_project_snippet_path(project.namespace, project, private_snippet) }
+ subject { project_snippet_path(project, private_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -83,7 +83,7 @@ describe "Public Project Snippets Access", feature: true do
describe "GET /:project_path/snippets/:id/raw" do
context "for a public snippet" do
- subject { raw_namespace_project_snippet_path(project.namespace, project, public_snippet) }
+ subject { raw_project_snippet_path(project, public_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -97,7 +97,7 @@ describe "Public Project Snippets Access", feature: true do
end
context "for an internal snippet" do
- subject { raw_namespace_project_snippet_path(project.namespace, project, internal_snippet) }
+ subject { raw_project_snippet_path(project, internal_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -111,7 +111,7 @@ describe "Public Project Snippets Access", feature: true do
end
context "for a private snippet" do
- subject { raw_namespace_project_snippet_path(project.namespace, project, private_snippet) }
+ subject { raw_project_snippet_path(project, private_snippet) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb
index 5d6d1e79af2..b6367b88e17 100644
--- a/spec/features/signup_spec.rb
+++ b/spec/features/signup_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Signup', feature: true do
+feature 'Signup' do
describe 'signup with no errors' do
context "when sending confirmation email" do
before do
diff --git a/spec/features/snippets/explore_spec.rb b/spec/features/snippets/explore_spec.rb
index ec75817b942..835fd90adc8 100644
--- a/spec/features/snippets/explore_spec.rb
+++ b/spec/features/snippets/explore_spec.rb
@@ -1,12 +1,12 @@
require 'rails_helper'
-feature 'Explore Snippets', feature: true do
+feature 'Explore Snippets' do
let!(:public_snippet) { create(:personal_snippet, :public) }
let!(:internal_snippet) { create(:personal_snippet, :internal) }
let!(:private_snippet) { create(:personal_snippet, :private) }
scenario 'User should see snippets that are not private' do
- gitlab_sign_in create(:user)
+ sign_in create(:user)
visit explore_snippets_path
expect(page).to have_content(public_snippet.title)
@@ -15,7 +15,7 @@ feature 'Explore Snippets', feature: true do
end
scenario 'External user should see only public snippets' do
- gitlab_sign_in create(:user, :external)
+ sign_in create(:user, :external)
visit explore_snippets_path
expect(page).to have_content(public_snippet.title)
diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb
index 3babb1c02cc..3a229612235 100644
--- a/spec/features/snippets/internal_snippet_spec.rb
+++ b/spec/features/snippets/internal_snippet_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'Internal Snippets', feature: true, js: true do
+feature 'Internal Snippets', js: true do
let(:internal_snippet) { create(:personal_snippet, :internal) }
describe 'normal user' do
before do
- gitlab_sign_in :user
+ sign_in(create(:user))
end
scenario 'sees internal snippets' do
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
index d310e7501ec..f1d0905738b 100644
--- a/spec/features/snippets/notes_on_personal_snippets_spec.rb
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Comments on personal snippets', :js, feature: true do
+describe 'Comments on personal snippets', :js do
include NoteInteractionHelpers
let!(:user) { create(:user) }
@@ -14,7 +14,7 @@ describe 'Comments on personal snippets', :js, feature: true do
let!(:other_note) { create(:note_on_personal_snippet) }
before do
- gitlab_sign_in user
+ sign_in user
visit snippet_path(snippet)
end
@@ -33,6 +33,7 @@ describe 'Comments on personal snippets', :js, feature: true do
expect(page).to have_selector('.note-emoji-button')
end
+ find('body').click # close dropdown
open_more_actions_dropdown(snippet_notes[1])
page.within("#notes-list li#note_#{snippet_notes[1].id}") do
diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb
index afd945a8555..bdeeca7187e 100644
--- a/spec/features/snippets/public_snippets_spec.rb
+++ b/spec/features/snippets/public_snippets_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'Public Snippets', :js, feature: true do
+feature 'Public Snippets', :js do
scenario 'Unauthenticated user should see public snippets' do
public_snippet = create(:personal_snippet, :public)
diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb
index 4c21e7321f4..cd66a2cb20c 100644
--- a/spec/features/snippets/search_snippets_spec.rb
+++ b/spec/features/snippets/search_snippets_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'Search Snippets', feature: true do
+feature 'Search Snippets' do
scenario 'User searches for snippets by title' do
public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle')
private_snippet = create(:personal_snippet, :private, title: 'Middle and End')
- gitlab_sign_in private_snippet.author
+ sign_in private_snippet.author
visit dashboard_snippets_path
page.within '.search' do
@@ -41,7 +41,7 @@ feature 'Search Snippets', feature: true do
CONTENT
)
- gitlab_sign_in create(:user)
+ sign_in create(:user)
visit dashboard_snippets_path
page.within '.search' do
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index 95fc1d2bb62..5a48f5774ca 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Snippet', :js, feature: true do
+feature 'Snippet', :js do
let(:project) { create(:project, :repository) }
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) }
diff --git a/spec/features/snippets/create_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index ac5c14ed427..a919f5fa20b 100644
--- a/spec/features/snippets/create_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -1,10 +1,12 @@
require 'rails_helper'
-feature 'Create Snippet', :js, feature: true do
+feature 'User creates snippet', :js do
include DropzoneHelper
+ let(:user) { create(:user) }
+
before do
- gitlab_sign_in :user
+ sign_in(user)
visit new_snippet_path
end
@@ -39,7 +41,7 @@ feature 'Create Snippet', :js, feature: true do
expect(page).to have_content('My Snippet')
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/temp/\h{32}/banana_sample\.gif\z})
+ expect(link).to match(%r{/uploads/system/temp/\h{32}/banana_sample\.gif\z})
visit(link)
expect(page.status_code).to eq(200)
@@ -57,7 +59,7 @@ feature 'Create Snippet', :js, feature: true do
wait_for_requests
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
+ expect(link).to match(%r{/uploads/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
visit(link)
expect(page.status_code).to eq(200)
@@ -82,7 +84,7 @@ feature 'Create Snippet', :js, feature: true do
end
expect(page).to have_content('Hello World!')
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
+ expect(link).to match(%r{/uploads/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
visit(link)
expect(page.status_code).to eq(200)
diff --git a/spec/features/snippets/user_deletes_snippet_spec.rb b/spec/features/snippets/user_deletes_snippet_spec.rb
new file mode 100644
index 00000000000..ae5b883c477
--- /dev/null
+++ b/spec/features/snippets/user_deletes_snippet_spec.rb
@@ -0,0 +1,19 @@
+require 'rails_helper'
+
+feature 'User deletes snippet' do
+ let(:user) { create(:user) }
+ let(:content) { 'puts "test"' }
+ let(:snippet) { create(:personal_snippet, :public, content: content, author: user) }
+
+ before do
+ sign_in(user)
+
+ visit snippet_path(snippet)
+ end
+
+ it 'deletes the snippet' do
+ first(:link, 'Delete').click
+
+ expect(page).not_to have_content(snippet.title)
+ end
+end
diff --git a/spec/features/snippets/edit_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb
index 860e1b156d6..26070e508e2 100644
--- a/spec/features/snippets/edit_snippet_spec.rb
+++ b/spec/features/snippets/user_edits_snippet_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'Edit Snippet', :js, feature: true do
+feature 'User edits snippet', :js do
include DropzoneHelper
let(:file_name) { 'test.rb' }
@@ -10,7 +10,7 @@ feature 'Edit Snippet', :js, feature: true do
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, author: user) }
before do
- gitlab_sign_in(user)
+ sign_in(user)
visit edit_snippet_path(snippet)
wait_for_requests
@@ -27,12 +27,32 @@ feature 'Edit Snippet', :js, feature: true do
it 'updates the snippet with files attached' do
dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- expect(page.find_field("personal_snippet_description").value).to have_content('banana_sample')
+ expect(page.find_field('personal_snippet_description').value).to have_content('banana_sample')
click_button('Save changes')
wait_for_requests
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z})
+ expect(link).to match(%r{/uploads/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z})
+ end
+
+ it 'updates the snippet to make it internal' do
+ choose 'Internal'
+
+ click_button 'Save changes'
+ wait_for_requests
+
+ expect(page).to have_no_xpath("//i[@class='fa fa-lock']")
+ expect(page).to have_xpath("//i[@class='fa fa-shield']")
+ end
+
+ it 'updates the snippet to make it public' do
+ choose 'Public'
+
+ click_button 'Save changes'
+ wait_for_requests
+
+ expect(page).to have_no_xpath("//i[@class='fa fa-lock']")
+ expect(page).to have_xpath("//i[@class='fa fa-globe']")
end
end
diff --git a/spec/features/snippets/user_snippets_spec.rb b/spec/features/snippets/user_snippets_spec.rb
index b971c6aab53..7bc27486787 100644
--- a/spec/features/snippets/user_snippets_spec.rb
+++ b/spec/features/snippets/user_snippets_spec.rb
@@ -1,13 +1,13 @@
require 'rails_helper'
-feature 'User Snippets', feature: true do
+feature 'User Snippets' do
let(:author) { create(:user) }
let!(:public_snippet) { create(:personal_snippet, :public, author: author, title: "This is a public snippet") }
let!(:internal_snippet) { create(:personal_snippet, :internal, author: author, title: "This is an internal snippet") }
let!(:private_snippet) { create(:personal_snippet, :private, author: author, title: "This is a private snippet") }
background do
- gitlab_sign_in author
+ sign_in author
visit dashboard_snippets_path
end
diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb
index 70b16bfc810..ae3b876f87c 100644
--- a/spec/features/snippets_spec.rb
+++ b/spec/features/snippets_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Snippets', feature: true do
+describe 'Snippets' do
context 'when the project has snippets' do
let(:project) { create(:empty_project, :public) }
let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) }
diff --git a/spec/features/tags/master_creates_tag_spec.rb b/spec/features/tags/master_creates_tag_spec.rb
index 52db3583dac..35e1ca32f67 100644
--- a/spec/features/tags/master_creates_tag_spec.rb
+++ b/spec/features/tags/master_creates_tag_spec.rb
@@ -1,17 +1,17 @@
require 'spec_helper'
-feature 'Master creates tag', feature: true do
+feature 'Master creates tag' do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'from tag list' do
before do
- visit namespace_project_tags_path(project.namespace, project)
+ visit project_tags_path(project)
end
scenario 'with an invalid name displays an error' do
@@ -36,7 +36,7 @@ feature 'Master creates tag', feature: true do
create_tag_in_form(tag: 'v3.0', ref: 'master', message: "Awesome tag message\n\n- hello\n- world")
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v3.0'))
+ project_tag_path(project, 'v3.0'))
expect(page).to have_content 'v3.0'
page.within 'pre.wrap' do
expect(page).to have_content "Awesome tag message\n\n- hello\n- world"
@@ -47,7 +47,7 @@ feature 'Master creates tag', feature: true do
create_tag_in_form(tag: 'v4.0', ref: 'master', desc: "Awesome release notes\n\n- hello\n- world")
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v4.0'))
+ project_tag_path(project, 'v4.0'))
expect(page).to have_content 'v4.0'
page.within '.description' do
expect(page).to have_content 'Awesome release notes'
@@ -72,7 +72,7 @@ feature 'Master creates tag', feature: true do
context 'from new tag page' do
before do
- visit new_namespace_project_tag_path(project.namespace, project)
+ visit new_project_tag_path(project)
end
it 'description has autocomplete', :js do
diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb
index 58f33e954f9..e3c904ef3aa 100644
--- a/spec/features/tags/master_deletes_tag_spec.rb
+++ b/spec/features/tags/master_deletes_tag_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Master deletes tag', feature: true do
+feature 'Master deletes tag' do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_tags_path(project.namespace, project)
+ sign_in(user)
+ visit project_tags_path(project)
end
context 'from the tags list page', js: true do
@@ -24,12 +24,12 @@ feature 'Master deletes tag', feature: true do
scenario 'deletes the tag' do
click_on 'v1.0.0'
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
+ project_tag_path(project, 'v1.0.0'))
click_on 'Delete tag'
expect(current_path).to eq(
- namespace_project_tags_path(project.namespace, project))
+ project_tags_path(project))
expect(page).not_to have_content 'v1.0.0'
end
end
diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb
index 18c8c4c511c..d6e84a1c685 100644
--- a/spec/features/tags/master_updates_tag_spec.rb
+++ b/spec/features/tags/master_updates_tag_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-feature 'Master updates tag', feature: true do
+feature 'Master updates tag' do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
- visit namespace_project_tags_path(project.namespace, project)
+ sign_in(user)
+ visit project_tags_path(project)
end
context 'from the tags list page' do
@@ -20,7 +20,7 @@ feature 'Master updates tag', feature: true do
click_button 'Save changes'
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v1.1.0'))
+ project_tag_path(project, 'v1.1.0'))
expect(page).to have_content 'v1.1.0'
expect(page).to have_content 'Awesome release notes'
end
@@ -45,7 +45,7 @@ feature 'Master updates tag', feature: true do
click_button 'Save changes'
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v1.1.0'))
+ project_tag_path(project, 'v1.1.0'))
expect(page).to have_content 'v1.1.0'
expect(page).to have_content 'Awesome release notes'
end
diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb
index 3c21fa06694..27936bc7f52 100644
--- a/spec/features/tags/master_views_tags_spec.rb
+++ b/spec/features/tags/master_views_tags_spec.rb
@@ -1,23 +1,23 @@
require 'spec_helper'
-feature 'Master views tags', feature: true do
+feature 'Master views tags' do
let(:user) { create(:user) }
before do
project.team << [user, :master]
- gitlab_sign_in(user)
+ sign_in(user)
end
context 'when project has no tags' do
let(:project) { create(:project_empty_repo) }
before do
- visit namespace_project_path(project.namespace, project)
+ visit project_path(project)
click_on 'README'
fill_in :commit_message, with: 'Add a README file', visible: true
# Remove pre-receive hook so we can push without auth
FileUtils.rm_f(File.join(project.repository.path, 'hooks', 'pre-receive'))
click_button 'Commit changes'
- visit namespace_project_tags_path(project.namespace, project)
+ visit project_tags_path(project)
end
scenario 'displays a specific message' do
@@ -30,15 +30,15 @@ feature 'Master views tags', feature: true do
let(:repository) { project.repository }
before do
- visit namespace_project_tags_path(project.namespace, project)
+ visit project_tags_path(project)
end
scenario 'avoids a N+1 query in branches index' do
- control_count = ActiveRecord::QueryRecorder.new { visit namespace_project_tags_path(project.namespace, project) }.count
+ control_count = ActiveRecord::QueryRecorder.new { visit project_tags_path(project) }.count
%w(one two three four five).each { |tag| repository.add_tag(user, tag, 'master', 'foo') }
- expect { visit namespace_project_tags_path(project.namespace, project) }.not_to exceed_query_limit(control_count)
+ expect { visit project_tags_path(project) }.not_to exceed_query_limit(control_count)
end
scenario 'views the tags list page' do
@@ -49,7 +49,7 @@ feature 'Master views tags', feature: true do
click_on 'v1.0.0'
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
+ project_tag_path(project, 'v1.0.0'))
expect(page).to have_content 'v1.0.0'
expect(page).to have_content 'This tag has no release notes.'
end
@@ -59,24 +59,24 @@ feature 'Master views tags', feature: true do
click_on 'v1.0.0'
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
+ project_tag_path(project, 'v1.0.0'))
click_on 'Browse files'
expect(current_path).to eq(
- namespace_project_tree_path(project.namespace, project, 'v1.0.0'))
+ project_tree_path(project, 'v1.0.0'))
end
scenario 'has a button to browse commits' do
click_on 'v1.0.0'
expect(current_path).to eq(
- namespace_project_tag_path(project.namespace, project, 'v1.0.0'))
+ project_tag_path(project, 'v1.0.0'))
click_on 'Browse commits'
expect(current_path).to eq(
- namespace_project_commits_path(project.namespace, project, 'v1.0.0'))
+ project_commits_path(project, 'v1.0.0'))
end
end
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index 51b1b8e2328..7e198ce0677 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Task Lists', feature: true do
+feature 'Task Lists' do
include Warden::Test::Helpers
let(:project) { create(:empty_project) }
@@ -59,10 +59,10 @@ feature 'Task Lists', feature: true do
end
def visit_issue(project, issue)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ visit project_issue_path(project, issue)
end
- describe 'for Issues', feature: true do
+ describe 'for Issues' do
describe 'multiple tasks', js: true do
let!(:issue) { create(:issue, description: markdown, author: user, project: project) }
@@ -98,7 +98,7 @@ feature 'Task Lists', feature: true do
end
it 'provides a summary on Issues#index' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
expect(page).to have_content("2 of 6 tasks completed")
end
end
@@ -116,7 +116,7 @@ feature 'Task Lists', feature: true do
end
it 'provides a summary on Issues#index' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
expect(page).to have_content("0 of 1 task completed")
end
@@ -135,7 +135,7 @@ feature 'Task Lists', feature: true do
end
it 'provides a summary on Issues#index' do
- visit namespace_project_issues_path(project.namespace, project)
+ visit project_issues_path(project)
expect(page).to have_content("1 of 1 task completed")
end
@@ -242,7 +242,7 @@ feature 'Task Lists', feature: true do
describe 'for Merge Requests' do
def visit_merge_request(project, merge)
- visit namespace_project_merge_request_path(project.namespace, project, merge)
+ visit project_merge_request_path(project, merge)
end
describe 'multiple tasks' do
@@ -281,7 +281,7 @@ feature 'Task Lists', feature: true do
end
it 'provides a summary on MergeRequests#index' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
expect(page).to have_content("2 of 6 tasks completed")
end
end
@@ -298,7 +298,7 @@ feature 'Task Lists', feature: true do
end
it 'provides a summary on MergeRequests#index' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
expect(page).to have_content("0 of 1 task completed")
end
end
@@ -315,7 +315,7 @@ feature 'Task Lists', feature: true do
end
it 'provides a summary on MergeRequests#index' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit project_merge_requests_path(project)
expect(page).to have_content("1 of 1 task completed")
end
end
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 5af2c0e9035..604fe326e96 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Triggers', feature: true, js: true do
+feature 'Triggers', js: true do
let(:trigger_title) { 'trigger desc' }
let(:user) { create(:user) }
let(:user2) { create(:user) }
@@ -14,7 +14,7 @@ feature 'Triggers', feature: true, js: true do
@project.team << [user2, :master]
@project.team << [guest_user, :guest]
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
end
describe 'create trigger workflow' do
@@ -42,7 +42,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'click on edit trigger opens edit trigger page' do
create(:ci_trigger, owner: user, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if edit page has correct descrption
find('a[title="Edit"]').click
@@ -51,7 +51,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'edit trigger and save' do
create(:ci_trigger, owner: user, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if edit page opens, then fill in new description and save
find('a[title="Edit"]').click
@@ -67,7 +67,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'edit "legacy" trigger and save' do
# Create new trigger without owner association, i.e. Legacy trigger
create(:ci_trigger, owner: nil, project: @project)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if the trigger can be edited and description is blank
find('a[title="Edit"]').click
@@ -84,7 +84,7 @@ feature 'Triggers', feature: true, js: true do
describe 'trigger "Take ownership" workflow' do
before(:each) do
create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
end
scenario 'button "Take ownership" has correct alert' do
@@ -106,7 +106,7 @@ feature 'Triggers', feature: true, js: true do
describe 'trigger "Revoke" workflow' do
before(:each) do
create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
end
scenario 'button "Revoke" has correct alert' do
@@ -131,7 +131,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'show "legacy" badge for legacy trigger' do
create(:ci_trigger, owner: nil, project: @project)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if trigger without owner (i.e. legacy) shows "legacy" badge and is editable
expect(page.find('.triggers-list')).to have_content 'legacy'
@@ -140,7 +140,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'show "invalid" badge for trigger with owner having insufficient permissions' do
create(:ci_trigger, owner: guest_user, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if trigger without owner (i.e. legacy) shows "legacy" badge and is non-editable
expect(page.find('.triggers-list')).to have_content 'invalid'
@@ -150,7 +150,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'do not show "Edit" or full token for not owned trigger' do
# Create trigger with user different from current_user
create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if trigger not owned by current_user shows only first few token chars and doesn't have copy-to-clipboard button
expect(page.find('.triggers-list')).to have_content(@project.triggers.first.token[0..3])
@@ -163,7 +163,7 @@ feature 'Triggers', feature: true, js: true do
scenario 'show "Edit" and full token for owned trigger' do
create(:ci_trigger, owner: user, project: @project, description: trigger_title)
- visit namespace_project_settings_ci_cd_path(@project.namespace, @project)
+ visit project_settings_ci_cd_path(@project)
# See if trigger shows full token and has copy-to-clipboard button
expect(page.find('.triggers-list')).to have_content @project.triggers.first.token
diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb
index 352f8ba70ac..d728dc59b3f 100644
--- a/spec/features/unsubscribe_links_spec.rb
+++ b/spec/features/unsubscribe_links_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Unsubscribe links', feature: true do
+describe 'Unsubscribe links' do
include Warden::Test::Helpers
let(:recipient) { create(:user) }
diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
index 797b7b3d50d..e8884bc1a00 100644
--- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
@@ -1,11 +1,11 @@
require 'rails_helper'
-feature 'User uploads avatar to group', feature: true do
+feature 'User uploads avatar to group' do
scenario 'they see the new avatar' do
user = create(:user)
group = create(:group)
group.add_owner(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit edit_group_path(group)
attach_file(
@@ -18,7 +18,7 @@ feature 'User uploads avatar to group', feature: true do
visit group_path(group)
- expect(page).to have_selector(%Q(img[src$="/uploads/system/group/avatar/#{group.id}/dk.png"]))
+ expect(page).to have_selector(%Q(img[data-src$="/uploads/-/system/group/avatar/#{group.id}/dk.png"]))
# Cheating here to verify something that isn't user-facing, but is important
expect(group.reload.avatar.file).to exist
diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
index a3f8027f4da..52003bb0859 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -1,9 +1,9 @@
require 'rails_helper'
-feature 'User uploads avatar to profile', feature: true do
+feature 'User uploads avatar to profile' do
scenario 'they see their new avatar' do
user = create(:user)
- gitlab_sign_in(user)
+ sign_in(user)
visit profile_path
attach_file(
@@ -16,7 +16,7 @@ feature 'User uploads avatar to profile', feature: true do
visit user_path(user)
- expect(page).to have_selector(%Q(img[src$="/uploads/system/user/avatar/#{user.id}/dk.png"]))
+ expect(page).to have_selector(%Q(img[data-src$="/uploads/-/system/user/avatar/#{user.id}/dk.png"]))
# Cheating here to verify something that isn't user-facing, but is important
expect(user.reload.avatar.file).to exist
diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb
index 77a1012762d..0654923d9a6 100644
--- a/spec/features/uploads/user_uploads_file_to_note_spec.rb
+++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'User uploads file to note', feature: true do
+feature 'User uploads file to note' do
include DropzoneHelper
let(:user) { create(:user) }
@@ -8,8 +8,8 @@ feature 'User uploads file to note', feature: true do
let(:issue) { create(:issue, project: project, author: user) }
before do
- gitlab_sign_in(user)
- visit namespace_project_issue_path(project.namespace, project, issue)
+ sign_in(user)
+ visit project_issue_path(project, issue)
end
context 'before uploading' do
diff --git a/spec/features/user_callout_spec.rb b/spec/features/user_callout_spec.rb
index 946a93f16e2..fa35fd7ebab 100644
--- a/spec/features/user_callout_spec.rb
+++ b/spec/features/user_callout_spec.rb
@@ -6,7 +6,7 @@ describe 'User Callouts', js: true do
let(:project) { create(:empty_project, path: 'gitlab', name: 'sample') }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :master]
end
diff --git a/spec/features/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb
index 1bd7e038939..670e8dda916 100644
--- a/spec/features/user_can_display_performance_bar_spec.rb
+++ b/spec/features/user_can_display_performance_bar_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'User can display performacne bar', :js do
+describe 'User can display performance bar', :js do
shared_examples 'performance bar is disabled' do
it 'does not show the performance bar by default' do
expect(page).not_to have_css('#peek')
@@ -27,28 +27,30 @@ describe 'User can display performacne bar', :js do
find('body').native.send_keys('pb')
end
- it 'does not show the performance bar by default' do
- expect(page).not_to have_css('#peek')
+ it 'shows the performance bar' do
+ expect(page).to have_css('#peek')
end
end
end
+ let(:group) { create(:group) }
+
context 'when user is logged-out' do
before do
visit root_path
end
- context 'when the gitlab_performance_bar feature is disabled' do
+ context 'when the performance_bar feature is disabled' do
before do
- Feature.disable('gitlab_performance_bar')
+ stub_application_setting(performance_bar_allowed_group_id: nil)
end
it_behaves_like 'performance bar is disabled'
end
- context 'when the gitlab_performance_bar feature is enabled' do
+ context 'when the performance_bar feature is enabled' do
before do
- Feature.enable('gitlab_performance_bar')
+ stub_application_setting(performance_bar_allowed_group_id: group.id)
end
it_behaves_like 'performance bar is disabled'
@@ -57,22 +59,25 @@ describe 'User can display performacne bar', :js do
context 'when user is logged-in' do
before do
- gitlab_sign_in(create(:user))
+ user = create(:user)
+
+ sign_in(user)
+ group.add_guest(user)
visit root_path
end
- context 'when the gitlab_performance_bar feature is disabled' do
+ context 'when the performance_bar feature is disabled' do
before do
- Feature.disable('gitlab_performance_bar')
+ stub_application_setting(performance_bar_allowed_group_id: nil)
end
it_behaves_like 'performance bar is disabled'
end
- context 'when the gitlab_performance_bar feature is enabled' do
+ context 'when the performance_bar feature is enabled' do
before do
- Feature.enable('gitlab_performance_bar')
+ stub_application_setting(performance_bar_allowed_group_id: group.id)
end
it_behaves_like 'performance bar is enabled'
diff --git a/spec/features/users/projects_spec.rb b/spec/features/users/projects_spec.rb
index 377b1a0148f..b961d2337ed 100644
--- a/spec/features/users/projects_spec.rb
+++ b/spec/features/users/projects_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Projects tab on a user profile', :feature, :js do
+describe 'Projects tab on a user profile', :js do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, namespace: user.namespace) }
let!(:project2) { create(:empty_project, namespace: user.namespace) }
@@ -8,7 +8,7 @@ describe 'Projects tab on a user profile', :feature, :js do
before do
allow(Project).to receive(:default_per_page).and_return(1)
- gitlab_sign_in(user)
+ sign_in(user)
visit user_path(user)
diff --git a/spec/features/users/rss_spec.rb b/spec/features/users/rss_spec.rb
index 797b317a9bb..7c5abe54d56 100644
--- a/spec/features/users/rss_spec.rb
+++ b/spec/features/users/rss_spec.rb
@@ -1,11 +1,12 @@
require 'spec_helper'
feature 'User RSS' do
+ let(:user) { create(:user) }
let(:path) { user_path(create(:user)) }
context 'when signed in' do
before do
- gitlab_sign_in(create(:user))
+ sign_in(user)
visit path
end
diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb
index 74c5cbd7887..13760b4c2fc 100644
--- a/spec/features/users/snippets_spec.rb
+++ b/spec/features/users/snippets_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Snippets tab on a user profile', feature: true, js: true do
+describe 'Snippets tab on a user profile', js: true do
context 'when the user has snippets' do
let(:user) { create(:user) }
@@ -24,7 +24,7 @@ describe 'Snippets tab on a user profile', feature: true, js: true do
let!(:other_snippet) { create(:snippet, :public) }
it 'contains only internal and public snippets of a user when a user is logged in' do
- gitlab_sign_in(:user)
+ sign_in(create(:user))
visit user_path(user)
page.within('.user-profile-nav') { click_link 'Snippets' }
wait_for_requests
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index 84af13d3e49..ff004d85272 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Users', feature: true, js: true do
+feature 'Users', js: true do
let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') }
scenario 'GET /users/sign_in creates a new user account' do
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index 85085bf305a..dd770fe5043 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -6,11 +6,11 @@ describe 'Project variables', js: true do
let(:variable) { create(:ci_variable, key: 'test_key', value: 'test value') }
before do
- gitlab_sign_in(user)
+ sign_in(user)
project.team << [user, :master]
project.variables << variable
- visit namespace_project_settings_ci_cd_path(project.namespace, project)
+ visit project_settings_ci_cd_path(project)
end
it 'shows list of variables' do
@@ -24,7 +24,7 @@ describe 'Project variables', js: true do
fill_in('variable_value', with: 'key value')
click_button('Add new variable')
- expect(page).to have_content('Variables were successfully updated.')
+ expect(page).to have_content('Variable was successfully created.')
page.within('.variables-table') do
expect(page).to have_content('key')
expect(page).to have_content('No')
@@ -36,7 +36,7 @@ describe 'Project variables', js: true do
fill_in('variable_value', with: '')
click_button('Add new variable')
- expect(page).to have_content('Variables were successfully updated.')
+ expect(page).to have_content('Variable was successfully created.')
page.within('.variables-table') do
expect(page).to have_content('new_key')
end
@@ -48,7 +48,7 @@ describe 'Project variables', js: true do
check('Protected')
click_button('Add new variable')
- expect(page).to have_content('Variables were successfully updated.')
+ expect(page).to have_content('Variable was successfully created.')
page.within('.variables-table') do
expect(page).to have_content('key')
expect(page).to have_content('Yes')
@@ -82,7 +82,7 @@ describe 'Project variables', js: true do
it 'deletes variable' do
page.within('.variables-table') do
- find('.btn-variable-delete').click
+ click_on 'Remove'
end
expect(page).not_to have_selector('variables-table')
@@ -90,7 +90,7 @@ describe 'Project variables', js: true do
it 'edits variable' do
page.within('.variables-table') do
- find('.btn-variable-edit').click
+ click_on 'Update'
end
expect(page).to have_content('Update variable')
@@ -104,7 +104,7 @@ describe 'Project variables', js: true do
it 'edits variable with empty value' do
page.within('.variables-table') do
- find('.btn-variable-edit').click
+ click_on 'Update'
end
expect(page).to have_content('Update variable')
@@ -117,7 +117,7 @@ describe 'Project variables', js: true do
it 'edits variable to be protected' do
page.within('.variables-table') do
- find('.btn-variable-edit').click
+ click_on 'Update'
end
expect(page).to have_content('Update variable')
@@ -132,7 +132,7 @@ describe 'Project variables', js: true do
project.variables.first.update(protected: true)
page.within('.variables-table') do
- find('.btn-variable-edit').click
+ click_on 'Update'
end
expect(page).to have_content('Update variable')
diff --git a/spec/finders/access_requests_finder_spec.rb b/spec/finders/access_requests_finder_spec.rb
index c7278e971ae..1d0c15392b2 100644
--- a/spec/finders/access_requests_finder_spec.rb
+++ b/spec/finders/access_requests_finder_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe AccessRequestsFinder, services: true do
+describe AccessRequestsFinder do
let(:user) { create(:user) }
let(:access_requester) { create(:user) }
diff --git a/spec/finders/admin/projects_finder_spec.rb b/spec/finders/admin/projects_finder_spec.rb
new file mode 100644
index 00000000000..296d6c51d04
--- /dev/null
+++ b/spec/finders/admin/projects_finder_spec.rb
@@ -0,0 +1,136 @@
+require 'spec_helper'
+
+describe Admin::ProjectsFinder do
+ describe '#execute' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group, :public) }
+
+ let!(:private_project) do
+ create(:empty_project, :private, name: 'A', path: 'A')
+ end
+
+ let!(:internal_project) do
+ create(:empty_project, :internal, group: group, name: 'B', path: 'B')
+ end
+
+ let!(:public_project) do
+ create(:empty_project, :public, group: group, name: 'C', path: 'C')
+ end
+
+ let!(:shared_project) do
+ create(:empty_project, :private, name: 'D', path: 'D')
+ end
+
+ let(:params) { {} }
+ let(:current_user) { user }
+ let(:project_ids_relation) { nil }
+ let(:finder) { described_class.new(params: params, current_user: current_user) }
+
+ subject { finder.execute.to_a }
+
+ context 'without a user' do
+ let(:current_user) { nil }
+
+ it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) }
+ end
+
+ context 'with a user' do
+ it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) }
+ end
+
+ context 'filter by namespace_id' do
+ let(:namespace) { create(:namespace) }
+ let!(:project_in_namespace) { create(:empty_project, namespace: namespace) }
+ let(:params) { { namespace_id: namespace.id } }
+
+ it { is_expected.to eq([project_in_namespace]) }
+ end
+
+ context 'filter by visibility_level' do
+ before do
+ private_project.add_master(user)
+ end
+
+ context 'private' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::PRIVATE } }
+
+ it { is_expected.to match_array([shared_project, private_project]) }
+ end
+
+ context 'internal' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::INTERNAL } }
+
+ it { is_expected.to eq([internal_project]) }
+ end
+
+ context 'public' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::PUBLIC } }
+
+ it { is_expected.to eq([public_project]) }
+ end
+ end
+
+ context 'filter by push' do
+ let(:pushed_event) { create(:event, :pushed) }
+ let!(:project_with_push) { pushed_event.project }
+ let(:params) { { with_push: true } }
+
+ it { is_expected.to eq([project_with_push]) }
+ end
+
+ context 'filter by abandoned' do
+ before do
+ private_project.update(last_activity_at: Time.zone.now - 6.months - 1.minute)
+ end
+
+ let(:params) { { abandoned: true } }
+
+ it { is_expected.to eq([private_project]) }
+ end
+
+ context 'filter by last_repository_check_failed' do
+ before do
+ private_project.update(last_repository_check_failed: true)
+ end
+
+ let(:params) { { last_repository_check_failed: true } }
+
+ it { is_expected.to eq([private_project]) }
+ end
+
+ context 'filter by archived' do
+ let!(:archived_project) { create(:empty_project, :public, :archived, name: 'E', path: 'E') }
+
+ context 'archived=false' do
+ let(:params) { { archived: false } }
+
+ it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) }
+ end
+
+ context 'archived=true' do
+ let(:params) { { archived: true } }
+
+ it { is_expected.to match_array([archived_project, shared_project, public_project, internal_project, private_project]) }
+ end
+ end
+
+ context 'filter by personal' do
+ let!(:personal_project) { create(:empty_project, namespace: user.namespace) }
+ let(:params) { { personal: true } }
+
+ it { is_expected.to eq([personal_project]) }
+ end
+
+ context 'filter by name' do
+ let(:params) { { name: 'C' } }
+
+ it { is_expected.to match_array([shared_project, public_project, private_project]) }
+ end
+
+ context 'sorting' do
+ let(:params) { { sort: 'name_asc' } }
+
+ it { is_expected.to eq([private_project, internal_project, public_project, shared_project]) }
+ end
+ end
+end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 8ace1fb5751..bef4fd44331 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -59,6 +59,23 @@ describe IssuesFinder do
end
end
+ context 'filtering by group milestone' do
+ let!(:group) { create(:group, :public) }
+ let(:group_milestone) { create(:milestone, group: group) }
+ let!(:group_member) { create(:group_member, group: group, user: user) }
+ let(:params) { { milestone_title: group_milestone.title } }
+
+ before do
+ project2.update(namespace: group)
+ issue2.update(milestone: group_milestone)
+ issue3.update(milestone: group_milestone)
+ end
+
+ it 'returns issues assigned to that group milestone' do
+ expect(issues).to contain_exactly(issue2, issue3)
+ end
+ end
+
context 'filtering by no milestone' do
let(:params) { { milestone_title: Milestone::None.title } }
@@ -295,22 +312,121 @@ describe IssuesFinder do
end
end
- describe '.not_restricted_by_confidentiality' do
- let(:authorized_user) { create(:user) }
- let(:project) { create(:empty_project, namespace: authorized_user.namespace) }
- let!(:public_issue) { create(:issue, project: project) }
- let!(:confidential_issue) { create(:issue, project: project, confidential: true) }
+ describe '#with_confidentiality_access_check' do
+ let(:guest) { create(:user) }
+ set(:authorized_user) { create(:user) }
+ set(:project) { create(:empty_project, namespace: authorized_user.namespace) }
+ set(:public_issue) { create(:issue, project: project) }
+ set(:confidential_issue) { create(:issue, project: project, confidential: true) }
- it 'returns non confidential issues for nil user' do
- expect(described_class.send(:not_restricted_by_confidentiality, nil)).to include(public_issue)
- end
+ context 'when no project filter is given' do
+ let(:params) { {} }
+
+ context 'for an anonymous user' do
+ subject { described_class.new(nil, params).with_confidentiality_access_check }
- it 'returns non confidential issues for user not authorized for the issues projects' do
- expect(described_class.send(:not_restricted_by_confidentiality, user)).to include(public_issue)
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+ end
+
+ context 'for a user without project membership' do
+ subject { described_class.new(user, params).with_confidentiality_access_check }
+
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+ end
+
+ context 'for a guest user' do
+ subject { described_class.new(guest, params).with_confidentiality_access_check }
+
+ before do
+ project.add_guest(guest)
+ end
+
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+ end
+
+ context 'for a project member with access to view confidential issues' do
+ subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
+
+ it 'returns all issues' do
+ expect(subject).to include(public_issue, confidential_issue)
+ end
+ end
end
- it 'returns all issues for user authorized for the issues projects' do
- expect(described_class.send(:not_restricted_by_confidentiality, authorized_user)).to include(public_issue, confidential_issue)
+ context 'when searching within a specific project' do
+ let(:params) { { project_id: project.id } }
+
+ context 'for an anonymous user' do
+ subject { described_class.new(nil, params).with_confidentiality_access_check }
+
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+
+ it 'does not filter by confidentiality' do
+ expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
+
+ subject
+ end
+ end
+
+ context 'for a user without project membership' do
+ subject { described_class.new(user, params).with_confidentiality_access_check }
+
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+
+ it 'filters by confidentiality' do
+ expect(Issue).to receive(:where).with(a_string_matching('confidential'), anything)
+
+ subject
+ end
+ end
+
+ context 'for a guest user' do
+ subject { described_class.new(guest, params).with_confidentiality_access_check }
+
+ before do
+ project.add_guest(guest)
+ end
+
+ it 'returns only public issues' do
+ expect(subject).to include(public_issue)
+ expect(subject).not_to include(confidential_issue)
+ end
+
+ it 'filters by confidentiality' do
+ expect(Issue).to receive(:where).with(a_string_matching('confidential'), anything)
+
+ subject
+ end
+ end
+
+ context 'for a project member with access to view confidential issues' do
+ subject { described_class.new(authorized_user, params).with_confidentiality_access_check }
+
+ it 'returns all issues' do
+ expect(subject).to include(public_issue, confidential_issue)
+ end
+
+ it 'does not filter by confidentiality' do
+ expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything)
+
+ subject
+ end
+ end
end
end
end
diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb
index 1724cdba830..95d96354b77 100644
--- a/spec/finders/labels_finder_spec.rb
+++ b/spec/finders/labels_finder_spec.rb
@@ -49,12 +49,12 @@ describe LabelsFinder do
end
context 'filtering by group_id' do
- it 'returns labels available for any project within the group' do
+ it 'returns labels available for any non-archived project within the group' do
group_1.add_developer(user)
-
+ project_1.archive!
finder = described_class.new(user, group_id: group_1.id)
- expect(finder.execute).to eq [group_label_2, project_label_1, group_label_1, project_label_5]
+ expect(finder.execute).to eq [group_label_2, group_label_1, project_label_5]
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 5eb26de6c92..b46218bf72e 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -47,6 +47,25 @@ describe MergeRequestsFinder do
expect(merge_requests).to contain_exactly(merge_request1)
end
+ context 'filtering by group milestone' do
+ let!(:group) { create(:group, :public) }
+ let(:group_milestone) { create(:milestone, group: group) }
+ let!(:group_member) { create(:group_member, group: group, user: user) }
+ let(:params) { { milestone_title: group_milestone.title } }
+
+ before do
+ project2.update(namespace: group)
+ merge_request2.update(milestone: group_milestone)
+ merge_request3.update(milestone: group_milestone)
+ end
+
+ it 'returns issues assigned to that group milestone' do
+ merge_requests = described_class.new(user, params).execute
+
+ expect(merge_requests).to contain_exactly(merge_request2, merge_request3)
+ end
+ end
+
context 'with created_after and created_before params' do
let(:project4) { create(:empty_project, forked_from_project: project1) }
diff --git a/spec/finders/milestones_finder_spec.rb b/spec/finders/milestones_finder_spec.rb
new file mode 100644
index 00000000000..32ec983c5b8
--- /dev/null
+++ b/spec/finders/milestones_finder_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+describe MilestonesFinder do
+ let(:group) { create(:group) }
+ let(:project_1) { create(:empty_project, namespace: group) }
+ let(:project_2) { create(:empty_project, namespace: group) }
+ let!(:milestone_1) { create(:milestone, group: group, title: 'one test', due_date: Date.today) }
+ let!(:milestone_2) { create(:milestone, group: group) }
+ let!(:milestone_3) { create(:milestone, project: project_1, state: 'active', due_date: Date.tomorrow) }
+ let!(:milestone_4) { create(:milestone, project: project_2, state: 'active') }
+
+ it 'it returns milestones for projects' do
+ result = described_class.new(project_ids: [project_1.id, project_2.id], state: 'all').execute
+
+ expect(result).to contain_exactly(milestone_3, milestone_4)
+ end
+
+ it 'returns milestones for groups' do
+ result = described_class.new(group_ids: group.id, state: 'all').execute
+
+ expect(result).to contain_exactly(milestone_1, milestone_2)
+ end
+
+ it 'returns milestones for groups and projects' do
+ result = described_class.new(project_ids: [project_1.id, project_2.id], group_ids: group.id, state: 'all').execute
+
+ expect(result).to contain_exactly(milestone_1, milestone_2, milestone_3, milestone_4)
+ end
+
+ context 'with filters' do
+ let(:params) do
+ {
+ project_ids: [project_1.id, project_2.id],
+ group_ids: group.id,
+ state: 'all'
+ }
+ end
+
+ before do
+ milestone_1.close
+ milestone_3.close
+ end
+
+ it 'filters by active state' do
+ params[:state] = 'active'
+ result = described_class.new(params).execute
+
+ expect(result).to contain_exactly(milestone_2, milestone_4)
+ end
+
+ it 'filters by closed state' do
+ params[:state] = 'closed'
+ result = described_class.new(params).execute
+
+ expect(result).to contain_exactly(milestone_1, milestone_3)
+ end
+
+ it 'filters by title' do
+ result = described_class.new(params.merge(title: 'one test')).execute
+
+ expect(result.to_a).to contain_exactly(milestone_1)
+ end
+ end
+
+ context 'with order' do
+ let(:params) do
+ {
+ project_ids: [project_1.id, project_2.id],
+ group_ids: group.id,
+ state: 'all'
+ }
+ end
+
+ it "default orders by due date" do
+ result = described_class.new(params).execute
+
+ expect(result.first).to eq(milestone_1)
+ expect(result.second).to eq(milestone_3)
+ end
+
+ it "orders by parameter" do
+ result = described_class.new(params.merge(order: 'id DESC')).execute
+
+ expect(result.first).to eq(milestone_4)
+ expect(result.second).to eq(milestone_3)
+ expect(result.third).to eq(milestone_2)
+ expect(result.fourth).to eq(milestone_1)
+ end
+ end
+end
diff --git a/spec/finders/users_finder_spec.rb b/spec/finders/users_finder_spec.rb
index 780b309b45e..1bab6d64388 100644
--- a/spec/finders/users_finder_spec.rb
+++ b/spec/finders/users_finder_spec.rb
@@ -45,6 +45,17 @@ describe UsersFinder do
expect(users).to contain_exactly(user, user1, user2, omniauth_user)
end
+
+ it 'filters by created_at' do
+ filtered_user_before = create(:user, created_at: 3.days.ago)
+ filtered_user_after = create(:user, created_at: Time.now + 3.days)
+
+ users = described_class.new(user,
+ created_after: 2.days.ago,
+ created_before: Time.now + 2.days).execute
+
+ expect(users.map(&:username)).not_to include([filtered_user_before.username, filtered_user_after.username])
+ end
end
context 'with an admin user' do
diff --git a/spec/fixtures/api/schemas/entities/merge_request.json b/spec/fixtures/api/schemas/entities/merge_request.json
index b6a59a6cc47..7ffa82fc4bd 100644
--- a/spec/fixtures/api/schemas/entities/merge_request.json
+++ b/spec/fixtures/api/schemas/entities/merge_request.json
@@ -75,6 +75,7 @@
"additionalProperties": false
},
"target_branch_commits_path": { "type": "string" },
+ "target_branch_tree_path": { "type": "string" },
"source_branch_path": { "type": "string" },
"conflict_resolution_path": { "type": ["string", "null"] },
"cancel_merge_when_pipeline_succeeds_path": { "type": "string" },
diff --git a/spec/fixtures/api/schemas/prometheus/additional_metrics_query_result.json b/spec/fixtures/api/schemas/prometheus/additional_metrics_query_result.json
new file mode 100644
index 00000000000..47b5d283b8c
--- /dev/null
+++ b/spec/fixtures/api/schemas/prometheus/additional_metrics_query_result.json
@@ -0,0 +1,58 @@
+{
+ "items": {
+ "properties": {
+ "group": {
+ "type": "string"
+ },
+ "metrics": {
+ "items": {
+ "properties": {
+ "queries": {
+ "items": {
+ "properties": {
+ "query_range": {
+ "type": "string"
+ },
+ "query": {
+ "type": "string"
+ },
+ "result": {
+ "type": "any"
+ }
+ },
+ "type": "object"
+ },
+ "type": "array"
+ },
+ "title": {
+ "type": "string"
+ },
+ "weight": {
+ "type": "integer"
+ },
+ "y_label": {
+ "type": "string"
+ }
+ },
+ "type": "object"
+ },
+ "required": [
+ "metrics",
+ "title",
+ "weight"
+ ],
+ "type": "array"
+ },
+ "priority": {
+ "type": "integer"
+ }
+ },
+ "type": "object"
+ },
+ "required": [
+ "group",
+ "priority",
+ "metrics"
+ ],
+ "type": "array"
+} \ No newline at end of file
diff --git a/spec/fixtures/api/schemas/public_api/v3/issues.json b/spec/fixtures/api/schemas/public_api/v3/issues.json
index f2ee9c925ae..51b0822bc66 100644
--- a/spec/fixtures/api/schemas/public_api/v3/issues.json
+++ b/spec/fixtures/api/schemas/public_api/v3/issues.json
@@ -22,7 +22,8 @@
"properties": {
"id": { "type": "integer" },
"iid": { "type": "integer" },
- "project_id": { "type": "integer" },
+ "project_id": { "type": ["integer", "null"] },
+ "group_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
diff --git a/spec/fixtures/api/schemas/public_api/v3/merge_requests.json b/spec/fixtures/api/schemas/public_api/v3/merge_requests.json
index 01f9fbb2c89..b5c74bcc26e 100644
--- a/spec/fixtures/api/schemas/public_api/v3/merge_requests.json
+++ b/spec/fixtures/api/schemas/public_api/v3/merge_requests.json
@@ -53,7 +53,8 @@
"properties": {
"id": { "type": "integer" },
"iid": { "type": "integer" },
- "project_id": { "type": "integer" },
+ "project_id": { "type": ["integer", "null"] },
+ "group_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
diff --git a/spec/fixtures/api/schemas/public_api/v4/branch.json b/spec/fixtures/api/schemas/public_api/v4/branch.json
new file mode 100644
index 00000000000..a3581178974
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/branch.json
@@ -0,0 +1,20 @@
+{
+ "type": "object",
+ "required" : [
+ "name",
+ "commit",
+ "merged",
+ "protected",
+ "developers_can_push",
+ "developers_can_merge"
+ ],
+ "properties" : {
+ "name": { "type": "string" },
+ "commit": { "$ref": "commit/basic.json" },
+ "merged": { "type": "boolean" },
+ "protected": { "type": "boolean" },
+ "developers_can_push": { "type": "boolean" },
+ "developers_can_merge": { "type": "boolean" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/branches.json b/spec/fixtures/api/schemas/public_api/v4/branches.json
new file mode 100644
index 00000000000..854c902b485
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/branches.json
@@ -0,0 +1,4 @@
+{
+ "type": "array",
+ "items": { "$ref": "branch.json" }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/commit/basic.json b/spec/fixtures/api/schemas/public_api/v4/commit/basic.json
new file mode 100644
index 00000000000..9d99628a286
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/commit/basic.json
@@ -0,0 +1,37 @@
+{
+ "type": "object",
+ "required" : [
+ "id",
+ "short_id",
+ "title",
+ "created_at",
+ "parent_ids",
+ "message",
+ "author_name",
+ "author_email",
+ "authored_date",
+ "committer_name",
+ "committer_email",
+ "committed_date"
+ ],
+ "properties" : {
+ "id": { "type": ["string", "null"] },
+ "short_id": { "type": ["string", "null"] },
+ "title": { "type": "string" },
+ "created_at": { "type": "date" },
+ "parent_ids": {
+ "type": ["array", "null"],
+ "items": {
+ "type": "string",
+ "additionalProperties": false
+ }
+ },
+ "message": { "type": "string" },
+ "author_name": { "type": "string" },
+ "author_email": { "type": "string" },
+ "authored_date": { "type": "date" },
+ "committer_name": { "type": "string" },
+ "committer_email": { "type": "string" },
+ "committed_date": { "type": "date" }
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/issues.json b/spec/fixtures/api/schemas/public_api/v4/issues.json
index 2d1c84ee93d..bd6bfc03199 100644
--- a/spec/fixtures/api/schemas/public_api/v4/issues.json
+++ b/spec/fixtures/api/schemas/public_api/v4/issues.json
@@ -22,7 +22,8 @@
"properties": {
"id": { "type": "integer" },
"iid": { "type": "integer" },
- "project_id": { "type": "integer" },
+ "project_id": { "type": ["integer", "null"] },
+ "group_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
diff --git a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
index 51642e8cbb8..60aa47c1259 100644
--- a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
+++ b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json
@@ -53,7 +53,8 @@
"properties": {
"id": { "type": "integer" },
"iid": { "type": "integer" },
- "project_id": { "type": "integer" },
+ "project_id": { "type": ["integer", "null"] },
+ "group_id": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"state": { "type": "string" },
diff --git a/spec/fixtures/api/schemas/public_api/v4/user/admin.json b/spec/fixtures/api/schemas/public_api/v4/user/admin.json
new file mode 100644
index 00000000000..f733914fbf8
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/user/admin.json
@@ -0,0 +1,34 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "username",
+ "email",
+ "name",
+ "state",
+ "avatar_url",
+ "web_url",
+ "created_at",
+ "is_admin",
+ "bio",
+ "location",
+ "skype",
+ "linkedin",
+ "twitter",
+ "website_url",
+ "organization",
+ "last_sign_in_at",
+ "confirmed_at",
+ "color_scheme_id",
+ "projects_limit",
+ "current_sign_in_at",
+ "identities",
+ "can_create_group",
+ "can_create_project",
+ "two_factor_enabled",
+ "external"
+ ],
+ "properties": {
+ "$ref": "full.json"
+ }
+}
diff --git a/spec/fixtures/config/kubeconfig-without-ca.yml b/spec/fixtures/config/kubeconfig-without-ca.yml
new file mode 100644
index 00000000000..b2cb989d548
--- /dev/null
+++ b/spec/fixtures/config/kubeconfig-without-ca.yml
@@ -0,0 +1,18 @@
+---
+apiVersion: v1
+clusters:
+- name: gitlab-deploy
+ cluster:
+ server: https://kube.domain.com
+contexts:
+- name: gitlab-deploy
+ context:
+ cluster: gitlab-deploy
+ namespace: NAMESPACE
+ user: gitlab-deploy
+current-context: gitlab-deploy
+kind: Config
+users:
+- name: gitlab-deploy
+ user:
+ token: TOKEN
diff --git a/spec/fixtures/config/kubeconfig.yml b/spec/fixtures/config/kubeconfig.yml
new file mode 100644
index 00000000000..c4e8e573c32
--- /dev/null
+++ b/spec/fixtures/config/kubeconfig.yml
@@ -0,0 +1,19 @@
+---
+apiVersion: v1
+clusters:
+- name: gitlab-deploy
+ cluster:
+ server: https://kube.domain.com
+ certificate-authority-data: "UEVN\n"
+contexts:
+- name: gitlab-deploy
+ context:
+ cluster: gitlab-deploy
+ namespace: NAMESPACE
+ user: gitlab-deploy
+current-context: gitlab-deploy
+kind: Config
+users:
+- name: gitlab-deploy
+ user:
+ token: TOKEN
diff --git a/spec/fixtures/config/redis_cache_config_with_env.yml b/spec/fixtures/config/redis_cache_config_with_env.yml
new file mode 100644
index 00000000000..52fd5a06460
--- /dev/null
+++ b/spec/fixtures/config/redis_cache_config_with_env.yml
@@ -0,0 +1,2 @@
+test:
+ url: <%= ENV['TEST_GITLAB_REDIS_CACHE_URL'] %>
diff --git a/spec/fixtures/config/redis_cache_new_format_host.yml b/spec/fixtures/config/redis_cache_new_format_host.yml
new file mode 100644
index 00000000000..a24f3716391
--- /dev/null
+++ b/spec/fixtures/config/redis_cache_new_format_host.yml
@@ -0,0 +1,29 @@
+# redis://[:password@]host[:port][/db-number][?option=value]
+# more details: http://www.iana.org/assignments/uri-schemes/prov/redis
+development:
+ url: redis://:mynewpassword@localhost:6380/10
+ sentinels:
+ -
+ host: localhost
+ port: 26380 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26380 # point to sentinel, not to redis port
+test:
+ url: redis://:mynewpassword@localhost:6380/10
+ sentinels:
+ -
+ host: localhost
+ port: 26380 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26380 # point to sentinel, not to redis port
+production:
+ url: redis://:mynewpassword@localhost:6380/10
+ sentinels:
+ -
+ host: slave1
+ port: 26380 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26380 # point to sentinel, not to redis port
diff --git a/spec/fixtures/config/redis_cache_new_format_socket.yml b/spec/fixtures/config/redis_cache_new_format_socket.yml
new file mode 100644
index 00000000000..3634c550163
--- /dev/null
+++ b/spec/fixtures/config/redis_cache_new_format_socket.yml
@@ -0,0 +1,6 @@
+development:
+ url: unix:/path/to/redis.cache.sock
+test:
+ url: unix:/path/to/redis.cache.sock
+production:
+ url: unix:/path/to/redis.cache.sock
diff --git a/spec/fixtures/config/redis_cache_old_format_host.yml b/spec/fixtures/config/redis_cache_old_format_host.yml
new file mode 100644
index 00000000000..3609dcd022e
--- /dev/null
+++ b/spec/fixtures/config/redis_cache_old_format_host.yml
@@ -0,0 +1,5 @@
+# redis://[:password@]host[:port][/db-number][?option=value]
+# more details: http://www.iana.org/assignments/uri-schemes/prov/redis
+development: redis://:mypassword@localhost:6380/10
+test: redis://:mypassword@localhost:6380/10
+production: redis://:mypassword@localhost:6380/10
diff --git a/spec/fixtures/config/redis_cache_old_format_socket.yml b/spec/fixtures/config/redis_cache_old_format_socket.yml
new file mode 100644
index 00000000000..26fa0eda245
--- /dev/null
+++ b/spec/fixtures/config/redis_cache_old_format_socket.yml
@@ -0,0 +1,3 @@
+development: unix:/path/to/old/redis.cache.sock
+test: unix:/path/to/old/redis.cache.sock
+production: unix:/path/to/old/redis.cache.sock
diff --git a/spec/fixtures/config/redis_new_format_host.yml b/spec/fixtures/config/redis_new_format_host.yml
index 13772677a45..8d134d467e9 100644
--- a/spec/fixtures/config/redis_new_format_host.yml
+++ b/spec/fixtures/config/redis_new_format_host.yml
@@ -5,25 +5,25 @@ development:
sentinels:
-
host: localhost
- port: 26380 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: slave2
- port: 26381 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
test:
url: redis://:mynewpassword@localhost:6379/99
sentinels:
-
host: localhost
- port: 26380 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: slave2
- port: 26381 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
production:
url: redis://:mynewpassword@localhost:6379/99
sentinels:
-
host: slave1
- port: 26380 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: slave2
- port: 26381 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
diff --git a/spec/fixtures/config/redis_queues_config_with_env.yml b/spec/fixtures/config/redis_queues_config_with_env.yml
new file mode 100644
index 00000000000..d16a9d8a7f8
--- /dev/null
+++ b/spec/fixtures/config/redis_queues_config_with_env.yml
@@ -0,0 +1,2 @@
+test:
+ url: <%= ENV['TEST_GITLAB_REDIS_QUEUES_URL'] %>
diff --git a/spec/fixtures/config/redis_queues_new_format_host.yml b/spec/fixtures/config/redis_queues_new_format_host.yml
new file mode 100644
index 00000000000..1535584d779
--- /dev/null
+++ b/spec/fixtures/config/redis_queues_new_format_host.yml
@@ -0,0 +1,29 @@
+# redis://[:password@]host[:port][/db-number][?option=value]
+# more details: http://www.iana.org/assignments/uri-schemes/prov/redis
+development:
+ url: redis://:mynewpassword@localhost:6381/11
+ sentinels:
+ -
+ host: localhost
+ port: 26381 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26381 # point to sentinel, not to redis port
+test:
+ url: redis://:mynewpassword@localhost:6381/11
+ sentinels:
+ -
+ host: localhost
+ port: 26381 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26381 # point to sentinel, not to redis port
+production:
+ url: redis://:mynewpassword@localhost:6381/11
+ sentinels:
+ -
+ host: slave1
+ port: 26381 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26381 # point to sentinel, not to redis port
diff --git a/spec/fixtures/config/redis_queues_new_format_socket.yml b/spec/fixtures/config/redis_queues_new_format_socket.yml
new file mode 100644
index 00000000000..b488d84d022
--- /dev/null
+++ b/spec/fixtures/config/redis_queues_new_format_socket.yml
@@ -0,0 +1,6 @@
+development:
+ url: unix:/path/to/redis.queues.sock
+test:
+ url: unix:/path/to/redis.queues.sock
+production:
+ url: unix:/path/to/redis.queues.sock
diff --git a/spec/fixtures/config/redis_queues_old_format_host.yml b/spec/fixtures/config/redis_queues_old_format_host.yml
new file mode 100644
index 00000000000..6531748a8d7
--- /dev/null
+++ b/spec/fixtures/config/redis_queues_old_format_host.yml
@@ -0,0 +1,5 @@
+# redis://[:password@]host[:port][/db-number][?option=value]
+# more details: http://www.iana.org/assignments/uri-schemes/prov/redis
+development: redis://:mypassword@localhost:6381/11
+test: redis://:mypassword@localhost:6381/11
+production: redis://:mypassword@localhost:6381/11
diff --git a/spec/fixtures/config/redis_queues_old_format_socket.yml b/spec/fixtures/config/redis_queues_old_format_socket.yml
new file mode 100644
index 00000000000..53f5db72758
--- /dev/null
+++ b/spec/fixtures/config/redis_queues_old_format_socket.yml
@@ -0,0 +1,3 @@
+development: unix:/path/to/old/redis.queues.sock
+test: unix:/path/to/old/redis.queues.sock
+production: unix:/path/to/old/redis.queues.sock
diff --git a/spec/fixtures/config/redis_shared_state_config_with_env.yml b/spec/fixtures/config/redis_shared_state_config_with_env.yml
new file mode 100644
index 00000000000..eab7203d0de
--- /dev/null
+++ b/spec/fixtures/config/redis_shared_state_config_with_env.yml
@@ -0,0 +1,2 @@
+test:
+ url: <%= ENV['TEST_GITLAB_REDIS_SHARED_STATE_URL'] %>
diff --git a/spec/fixtures/config/redis_shared_state_new_format_host.yml b/spec/fixtures/config/redis_shared_state_new_format_host.yml
new file mode 100644
index 00000000000..1180b2b4a82
--- /dev/null
+++ b/spec/fixtures/config/redis_shared_state_new_format_host.yml
@@ -0,0 +1,29 @@
+# redis://[:password@]host[:port][/db-number][?option=value]
+# more details: http://www.iana.org/assignments/uri-schemes/prov/redis
+development:
+ url: redis://:mynewpassword@localhost:6382/12
+ sentinels:
+ -
+ host: localhost
+ port: 26382 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26382 # point to sentinel, not to redis port
+test:
+ url: redis://:mynewpassword@localhost:6382/12
+ sentinels:
+ -
+ host: localhost
+ port: 26382 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26382 # point to sentinel, not to redis port
+production:
+ url: redis://:mynewpassword@localhost:6382/12
+ sentinels:
+ -
+ host: slave1
+ port: 26382 # point to sentinel, not to redis port
+ -
+ host: slave2
+ port: 26382 # point to sentinel, not to redis port
diff --git a/spec/fixtures/config/redis_shared_state_new_format_socket.yml b/spec/fixtures/config/redis_shared_state_new_format_socket.yml
new file mode 100644
index 00000000000..1b0e699729e
--- /dev/null
+++ b/spec/fixtures/config/redis_shared_state_new_format_socket.yml
@@ -0,0 +1,6 @@
+development:
+ url: unix:/path/to/redis.shared_state.sock
+test:
+ url: unix:/path/to/redis.shared_state.sock
+production:
+ url: unix:/path/to/redis.shared_state.sock
diff --git a/spec/fixtures/config/redis_shared_state_old_format_host.yml b/spec/fixtures/config/redis_shared_state_old_format_host.yml
new file mode 100644
index 00000000000..fef5e768c5d
--- /dev/null
+++ b/spec/fixtures/config/redis_shared_state_old_format_host.yml
@@ -0,0 +1,5 @@
+# redis://[:password@]host[:port][/db-number][?option=value]
+# more details: http://www.iana.org/assignments/uri-schemes/prov/redis
+development: redis://:mypassword@localhost:6382/12
+test: redis://:mypassword@localhost:6382/12
+production: redis://:mypassword@localhost:6382/12
diff --git a/spec/fixtures/config/redis_shared_state_old_format_socket.yml b/spec/fixtures/config/redis_shared_state_old_format_socket.yml
new file mode 100644
index 00000000000..4746afbb5ef
--- /dev/null
+++ b/spec/fixtures/config/redis_shared_state_old_format_socket.yml
@@ -0,0 +1,3 @@
+development: unix:/path/to/old/redis.shared_state.sock
+test: unix:/path/to/old/redis.shared_state.sock
+production: unix:/path/to/old/redis.shared_state.sock
diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb
index 51a3e91d201..58b43805705 100644
--- a/spec/fixtures/markdown.md.erb
+++ b/spec/fixtures/markdown.md.erb
@@ -166,9 +166,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Issue in another project: <%= xissue.to_reference(project) %>
- Ignored in code: `<%= issue.to_reference %>`
- Ignored in links: [Link to <%= issue.to_reference %>](#issue-link)
-- Issue by URL: <%= urls.namespace_project_issue_url(issue.project.namespace, issue.project, issue) %>
+- Issue by URL: <%= urls.project_issue_url(issue.project, issue) %>
- Link to issue by reference: [Issue](<%= issue.to_reference %>)
-- Link to issue by URL: [Issue](<%= urls.namespace_project_issue_url(issue.project.namespace, issue.project, issue) %>)
+- Link to issue by URL: [Issue](<%= urls.project_issue_url(issue.project, issue) %>)
#### MergeRequestReferenceFilter
@@ -176,9 +176,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Merge request in another project: <%= xmerge_request.to_reference(project) %>
- Ignored in code: `<%= merge_request.to_reference %>`
- Ignored in links: [Link to <%= merge_request.to_reference %>](#merge-request-link)
-- Merge request by URL: <%= urls.namespace_project_merge_request_url(merge_request.project.namespace, merge_request.project, merge_request) %>
+- Merge request by URL: <%= urls.project_merge_request_url(merge_request.project, merge_request) %>
- Link to merge request by reference: [Merge request](<%= merge_request.to_reference %>)
-- Link to merge request by URL: [Merge request](<%= urls.namespace_project_merge_request_url(merge_request.project.namespace, merge_request.project, merge_request) %>)
+- Link to merge request by URL: [Merge request](<%= urls.project_merge_request_url(merge_request.project, merge_request) %>)
#### SnippetReferenceFilter
@@ -186,9 +186,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Snippet in another project: <%= xsnippet.to_reference(project) %>
- Ignored in code: `<%= snippet.to_reference %>`
- Ignored in links: [Link to <%= snippet.to_reference %>](#snippet-link)
-- Snippet by URL: <%= urls.namespace_project_snippet_url(snippet.project.namespace, snippet.project, snippet) %>
+- Snippet by URL: <%= urls.project_snippet_url(snippet.project, snippet) %>
- Link to snippet by reference: [Snippet](<%= snippet.to_reference %>)
-- Link to snippet by URL: [Snippet](<%= urls.namespace_project_snippet_url(snippet.project.namespace, snippet.project, snippet) %>)
+- Link to snippet by URL: [Snippet](<%= urls.project_snippet_url(snippet.project, snippet) %>)
#### CommitRangeReferenceFilter
@@ -196,9 +196,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Range in another project: <%= xcommit_range.to_reference(project) %>
- Ignored in code: `<%= commit_range.to_reference %>`
- Ignored in links: [Link to <%= commit_range.to_reference %>](#commit-range-link)
-- Range by URL: <%= urls.namespace_project_compare_url(commit_range.project.namespace, commit_range.project, commit_range.to_param) %>
+- Range by URL: <%= urls.project_compare_url(commit_range.project, commit_range.to_param) %>
- Link to range by reference: [Range](<%= commit_range.to_reference %>)
-- Link to range by URL: [Range](<%= urls.namespace_project_compare_url(commit_range.project.namespace, commit_range.project, commit_range.to_param) %>)
+- Link to range by URL: [Range](<%= urls.project_compare_url(commit_range.project, commit_range.to_param) %>)
#### CommitReferenceFilter
@@ -206,9 +206,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Commit in another project: <%= xcommit.to_reference(project) %>
- Ignored in code: `<%= commit.to_reference %>`
- Ignored in links: [Link to <%= commit.to_reference %>](#commit-link)
-- Commit by URL: <%= urls.namespace_project_commit_url(commit.project.namespace, commit.project, commit) %>
+- Commit by URL: <%= urls.project_commit_url(commit.project, commit) %>
- Link to commit by reference: [Commit](<%= commit.to_reference %>)
-- Link to commit by URL: [Commit](<%= urls.namespace_project_commit_url(commit.project.namespace, commit.project, commit) %>)
+- Link to commit by URL: [Commit](<%= urls.project_commit_url(commit.project, commit) %>)
#### LabelReferenceFilter
@@ -227,7 +227,7 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Milestone in another project: <%= xmilestone.to_reference(project) %>
- Ignored in code: `<%= simple_milestone.to_reference %>`
- Ignored in links: [Link to <%= simple_milestone.to_reference %>](#milestone-link)
-- Milestone by URL: <%= urls.namespace_project_milestone_url(milestone.project.namespace, milestone.project, milestone) %>
+- Milestone by URL: <%= urls.project_milestone_url(milestone.project, milestone) %>
- Link to milestone by URL: [Milestone](<%= milestone.to_reference %>)
### Task Lists
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 56daeffde27..ac5a58ac189 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -59,16 +59,16 @@ describe ApplicationHelper do
describe 'project_icon' do
it 'returns an url for the avatar' do
project = create(:empty_project, avatar: File.open(uploaded_image_temp_path))
- avatar_url = "/uploads/system/project/avatar/#{project.id}/banana_sample.gif"
+ avatar_url = "/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon(project.full_path).to_s)
- .to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />"
+ .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />"
allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)
- avatar_url = "#{gitlab_host}/uploads/system/project/avatar/#{project.id}/banana_sample.gif"
+ avatar_url = "#{gitlab_host}/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon(project.full_path).to_s)
- .to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />"
+ .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />"
end
it 'gives uploaded icon when present' do
@@ -76,8 +76,9 @@ describe ApplicationHelper do
allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true)
- avatar_url = "#{gitlab_host}#{namespace_project_avatar_path(project.namespace, project)}"
- expect(helper.project_icon(project.full_path).to_s).to match(image_tag(avatar_url))
+ avatar_url = "#{gitlab_host}#{project_avatar_path(project)}"
+ expect(helper.project_icon(project.full_path).to_s)
+ .to eq "<img data-src=\"#{avatar_url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />"
end
end
@@ -88,7 +89,7 @@ describe ApplicationHelper do
context 'when there is a matching user' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon(user.email).to_s)
- .to eq("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
context 'when an asset_host is set in the config' do
@@ -100,14 +101,14 @@ describe ApplicationHelper do
it 'returns an absolute URL on that asset host' do
expect(helper.avatar_icon(user.email, only_path: false).to_s)
- .to eq("#{asset_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("#{asset_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
context 'when only_path is set to false' do
it 'returns an absolute URL for the avatar' do
expect(helper.avatar_icon(user.email, only_path: false).to_s)
- .to eq("#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("#{gitlab_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
@@ -120,7 +121,7 @@ describe ApplicationHelper do
it 'returns a relative URL with the correct prefix' do
expect(helper.avatar_icon(user.email).to_s)
- .to eq("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("/gitlab/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
end
@@ -138,14 +139,14 @@ describe ApplicationHelper do
context 'when only_path is true' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon(user, only_path: true).to_s)
- .to eq("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
context 'when only_path is false' do
it 'returns an absolute URL for the avatar' do
expect(helper.avatar_icon(user, only_path: false).to_s)
- .to eq("#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
+ .to eq("#{gitlab_host}/uploads/-/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
end
@@ -292,7 +293,7 @@ describe ApplicationHelper do
let(:alternate_url) { 'http://company.example.com/getting-help' }
before do
- allow(current_application_settings).to receive(:help_page_support_url) { alternate_url }
+ stub_application_setting(help_page_support_url: alternate_url)
end
it 'returns the alternate support url' do
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
index a0e1265efff..c94fedd615b 100644
--- a/spec/helpers/auth_helper_spec.rb
+++ b/spec/helpers/auth_helper_spec.rb
@@ -70,7 +70,7 @@ describe AuthHelper do
end
end
- [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0].each do |provider|
+ [:twitter, :facebook, :google_oauth2, :gitlab, :github, :bitbucket, :crowd, :auth0, :authentiq].each do |provider|
it "returns false if the provider is #{provider}" do
expect(helper.unlink_allowed?(provider)).to be true
end
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index 049475a5408..d16fcf21e45 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -27,11 +27,11 @@ describe AvatarsHelper do
it 'displays user avatar' do
is_expected.to eq image_tag(
- avatar_icon(user, 16),
- class: 'avatar has-tooltip s16 ',
+ LazyImageTagHelper.placeholder_image,
+ class: 'avatar has-tooltip s16 lazy',
alt: "#{user.name}'s avatar",
title: user.name,
- data: { container: 'body' }
+ data: { container: 'body', src: avatar_icon(user, 16) }
)
end
@@ -40,22 +40,8 @@ describe AvatarsHelper do
it 'uses provided css_class' do
is_expected.to eq image_tag(
- avatar_icon(user, 16),
- class: "avatar has-tooltip s16 #{options[:css_class]}",
- alt: "#{user.name}'s avatar",
- title: user.name,
- data: { container: 'body' }
- )
- end
- end
-
- context 'with lazy parameter' do
- let(:options) { { user: user, lazy: true } }
-
- it 'uses data-src instead of src' do
- is_expected.to eq image_tag(
- '',
- class: 'avatar has-tooltip s16 ',
+ LazyImageTagHelper.placeholder_image,
+ class: "avatar has-tooltip s16 #{options[:css_class]} lazy",
alt: "#{user.name}'s avatar",
title: user.name,
data: { container: 'body', src: avatar_icon(user, 16) }
@@ -68,11 +54,11 @@ describe AvatarsHelper do
it 'uses provided size' do
is_expected.to eq image_tag(
- avatar_icon(user, options[:size]),
- class: "avatar has-tooltip s#{options[:size]} ",
+ LazyImageTagHelper.placeholder_image,
+ class: "avatar has-tooltip s#{options[:size]} lazy",
alt: "#{user.name}'s avatar",
title: user.name,
- data: { container: 'body' }
+ data: { container: 'body', src: avatar_icon(user, options[:size]) }
)
end
end
@@ -82,11 +68,11 @@ describe AvatarsHelper do
it 'uses provided url' do
is_expected.to eq image_tag(
- options[:url],
- class: 'avatar has-tooltip s16 ',
+ LazyImageTagHelper.placeholder_image,
+ class: 'avatar has-tooltip s16 lazy',
alt: "#{user.name}'s avatar",
title: user.name,
- data: { container: 'body' }
+ data: { container: 'body', src: options[:url] }
)
end
end
@@ -99,22 +85,22 @@ describe AvatarsHelper do
it 'prefers user parameter' do
is_expected.to eq image_tag(
- avatar_icon(user, 16),
- class: 'avatar has-tooltip s16 ',
+ LazyImageTagHelper.placeholder_image,
+ class: 'avatar has-tooltip s16 lazy',
alt: "#{user.name}'s avatar",
title: user.name,
- data: { container: 'body' }
+ data: { container: 'body', src: avatar_icon(user, 16) }
)
end
end
it 'uses user_name and user_email parameter if user is not present' do
is_expected.to eq image_tag(
- avatar_icon(options[:user_email], 16),
- class: 'avatar has-tooltip s16 ',
+ LazyImageTagHelper.placeholder_image,
+ class: 'avatar has-tooltip s16 lazy',
alt: "#{options[:user_name]}'s avatar",
title: options[:user_name],
- data: { container: 'body' }
+ data: { container: 'body', src: avatar_icon(options[:user_email], 16) }
)
end
end
diff --git a/spec/helpers/award_emoji_helper_spec.rb b/spec/helpers/award_emoji_helper_spec.rb
index 7dfd6a3f6b4..035960ed96e 100644
--- a/spec/helpers/award_emoji_helper_spec.rb
+++ b/spec/helpers/award_emoji_helper_spec.rb
@@ -40,7 +40,7 @@ describe AwardEmojiHelper do
it 'returns correct url' do
@project = merge_request.project
- expected_url = "/#{@project.namespace.path}/#{@project.path}/merge_requests/#{merge_request.id}/toggle_award_emoji"
+ expected_url = "/#{@project.namespace.path}/#{@project.path}/merge_requests/#{merge_request.iid}/toggle_award_emoji"
expect(helper.toggle_award_url(merge_request)).to eq(expected_url)
end
@@ -52,7 +52,7 @@ describe AwardEmojiHelper do
it 'returns correct url' do
@project = issue.project
- expected_url = "/#{@project.namespace.path}/#{@project.path}/issues/#{issue.id}/toggle_award_emoji"
+ expected_url = "/#{@project.namespace.path}/#{@project.path}/issues/#{issue.iid}/toggle_award_emoji"
expect(helper.toggle_award_url(issue)).to eq(expected_url)
end
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
new file mode 100644
index 00000000000..7ecb75da8ce
--- /dev/null
+++ b/spec/helpers/button_helper_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe ButtonHelper do
+ describe 'http_clone_button' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:has_tooltip_class) { 'has-tooltip' }
+
+ def element
+ element = helper.http_clone_button(project)
+
+ Nokogiri::HTML::DocumentFragment.parse(element).first_element_child
+ end
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'with internal auth enabled' do
+ context 'when user has a password' do
+ it 'shows no tooltip' do
+ expect(element.attr('class')).not_to include(has_tooltip_class)
+ end
+ end
+
+ context 'when user has password automatically set' do
+ let(:user) { create(:user, password_automatically_set: true) }
+
+ it 'shows a password tooltip' do
+ expect(element.attr('class')).to include(has_tooltip_class)
+ expect(element.attr('data-title')).to eq('Set a password on your account to pull or push via HTTP.')
+ end
+ end
+ end
+
+ context 'with internal auth disabled' do
+ before do
+ stub_application_setting(password_authentication_enabled?: false)
+ end
+
+ context 'when user has no personal access tokens' do
+ it 'has a personal access token tooltip ' do
+ expect(element.attr('class')).to include(has_tooltip_class)
+ expect(element.attr('data-title')).to eq('Create a personal access token on your account to pull or push via HTTP.')
+ end
+ end
+
+ context 'when user has a personal access token' do
+ it 'shows no tooltip' do
+ create(:personal_access_token, user: user)
+
+ expect(element.attr('class')).not_to include(has_tooltip_class)
+ end
+ end
+ end
+
+ context 'when user is ldap user' do
+ let(:user) { create(:omniauth_user, password_automatically_set: true) }
+
+ it 'shows no tooltip' do
+ expect(element.attr('class')).not_to include(has_tooltip_class)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 0d909e6e140..060c112e20d 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -12,19 +12,32 @@ describe DiffHelper do
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) }
describe 'diff_view' do
+ it 'uses the view param over the cookie' do
+ controller.params[:view] = 'parallel'
+ helper.request.cookies[:diff_view] = 'inline'
+
+ expect(helper.diff_view).to eq :parallel
+ end
+
+ it 'returns the default value when the view param is invalid' do
+ controller.params[:view] = 'invalid'
+
+ expect(helper.diff_view).to eq :inline
+ end
+
it 'returns a valid value when cookie is set' do
helper.request.cookies[:diff_view] = 'parallel'
expect(helper.diff_view).to eq :parallel
end
- it 'returns a default value when cookie is invalid' do
+ it 'returns the default value when cookie is invalid' do
helper.request.cookies[:diff_view] = 'invalid'
expect(helper.diff_view).to eq :inline
end
- it 'returns a default value when cookie is nil' do
+ it 'returns the default value when cookie is nil' do
expect(helper.request.cookies).to be_empty
expect(helper.diff_view).to eq :inline
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index c68e4f56b05..2390c1f3e5d 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -52,7 +52,7 @@ describe EmailsHelper do
)
expect(header_logo).to eq(
- %{<img style="height: 50px" src="/uploads/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
+ %{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
)
end
end
diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb
index 14847d0a49e..9aaed0edf87 100644
--- a/spec/helpers/gitlab_routing_helper_spec.rb
+++ b/spec/helpers/gitlab_routing_helper_spec.rb
@@ -1,48 +1,39 @@
require 'spec_helper'
describe GitlabRoutingHelper do
- describe 'Project URL helpers' do
- describe '#project_members_url' do
- let(:project) { build_stubbed(:empty_project) }
-
- it { expect(project_members_url(project)).to eq namespace_project_project_members_url(project.namespace, project) }
- end
+ let(:project) { build_stubbed(:empty_project) }
+ let(:group) { build_stubbed(:group) }
+ describe 'Project URL helpers' do
describe '#project_member_path' do
let(:project_member) { create(:project_member) }
- it { expect(project_member_path(project_member)).to eq namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) }
+ it { expect(project_member_path(project_member)).to eq project_project_member_path(project_member.source, project_member) }
end
describe '#request_access_project_members_path' do
- let(:project) { build_stubbed(:empty_project) }
-
- it { expect(request_access_project_members_path(project)).to eq request_access_namespace_project_project_members_path(project.namespace, project) }
+ it { expect(request_access_project_members_path(project)).to eq request_access_project_project_members_path(project) }
end
describe '#leave_project_members_path' do
- let(:project) { build_stubbed(:empty_project) }
-
- it { expect(leave_project_members_path(project)).to eq leave_namespace_project_project_members_path(project.namespace, project) }
+ it { expect(leave_project_members_path(project)).to eq leave_project_project_members_path(project) }
end
describe '#approve_access_request_project_member_path' do
let(:project_member) { create(:project_member) }
- it { expect(approve_access_request_project_member_path(project_member)).to eq approve_access_request_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) }
+ it { expect(approve_access_request_project_member_path(project_member)).to eq approve_access_request_project_project_member_path(project_member.source, project_member) }
end
describe '#resend_invite_project_member_path' do
let(:project_member) { create(:project_member) }
- it { expect(resend_invite_project_member_path(project_member)).to eq resend_invite_namespace_project_project_member_path(project_member.source.namespace, project_member.source, project_member) }
+ it { expect(resend_invite_project_member_path(project_member)).to eq resend_invite_project_project_member_path(project_member.source, project_member) }
end
end
describe 'Group URL helpers' do
describe '#group_members_url' do
- let(:group) { build_stubbed(:group) }
-
it { expect(group_members_url(group)).to eq group_group_members_url(group) }
end
@@ -53,14 +44,10 @@ describe GitlabRoutingHelper do
end
describe '#request_access_group_members_path' do
- let(:group) { build_stubbed(:group) }
-
it { expect(request_access_group_members_path(group)).to eq request_access_group_group_members_path(group) }
end
describe '#leave_group_members_path' do
- let(:group) { build_stubbed(:group) }
-
it { expect(leave_group_members_path(group)).to eq leave_group_group_members_path(group) }
end
@@ -76,4 +63,44 @@ describe GitlabRoutingHelper do
it { expect(resend_invite_group_member_path(group_member)).to eq resend_invite_group_group_member_path(group_member.source, group_member) }
end
end
+
+ describe '#milestone_path' do
+ context 'for a group milestone' do
+ let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) }
+
+ it 'links to the group milestone page' do
+ expect(milestone_path(milestone))
+ .to eq(group_milestone_path(group, milestone))
+ end
+ end
+
+ context 'for a project milestone' do
+ let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) }
+
+ it 'links to the project milestone page' do
+ expect(milestone_path(milestone))
+ .to eq(project_milestone_path(project, milestone))
+ end
+ end
+ end
+
+ describe '#milestone_url' do
+ context 'for a group milestone' do
+ let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) }
+
+ it 'links to the group milestone page' do
+ expect(milestone_url(milestone))
+ .to eq(group_milestone_url(group, milestone))
+ end
+ end
+
+ context 'for a project milestone' do
+ let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) }
+
+ it 'links to the project milestone page' do
+ expect(milestone_url(milestone))
+ .to eq(project_milestone_url(project, milestone))
+ end
+ end
+ end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index a7c06e577a2..3a246f10283 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe GroupsHelper do
+ include ApplicationHelper
+
describe 'group_icon' do
avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
@@ -9,7 +11,7 @@ describe GroupsHelper do
group.avatar = fixture_file_upload(avatar_file_path)
group.save!
expect(group_icon(group.path).to_s)
- .to match("/uploads/system/group/avatar/#{group.id}/banana_sample.gif")
+ .to match("/uploads/-/system/group/avatar/#{group.id}/banana_sample.gif")
end
it 'gives default avatar_icon when no avatar is present' do
@@ -81,4 +83,15 @@ describe GroupsHelper do
end
end
end
+
+ describe 'group_title', :nested_groups do
+ let(:group) { create(:group) }
+ let(:nested_group) { create(:group, parent: group) }
+ let(:deep_nested_group) { create(:group, parent: nested_group) }
+ let!(:very_deep_nested_group) { create(:group, parent: deep_nested_group) }
+
+ it 'outputs the groups in the correct order' do
+ expect(helper.group_title(very_deep_nested_group)).to match(/>#{group.name}<\/a>.*>#{nested_group.name}<\/a>.*>#{deep_nested_group.name}<\/a>/)
+ end
+ end
end
diff --git a/spec/helpers/hooks_helper_spec.rb b/spec/helpers/hooks_helper_spec.rb
new file mode 100644
index 00000000000..9f0004bf8cf
--- /dev/null
+++ b/spec/helpers/hooks_helper_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe HooksHelper do
+ let(:project) { create(:empty_project) }
+ let(:project_hook) { create(:project_hook, project: project) }
+ let(:system_hook) { create(:system_hook) }
+ let(:trigger) { 'push_events' }
+
+ describe '#link_to_test_hook' do
+ it 'returns project namespaced link' do
+ expect(helper.link_to_test_hook(project_hook, trigger))
+ .to include("href=\"#{test_project_hook_path(project, project_hook, trigger: trigger)}\"")
+ end
+
+ it 'returns admin namespaced link' do
+ expect(helper.link_to_test_hook(system_hook, trigger))
+ .to include("href=\"#{test_admin_hook_path(system_hook, trigger: trigger)}\"")
+ end
+ end
+end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 15cb620199d..7789cfa3554 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -60,7 +60,7 @@ describe IssuablesHelper do
end
end
- describe 'counter caching based on issuable type and params', :caching do
+ describe 'counter caching based on issuable type and params', :use_clean_rails_memory_store_caching do
let(:params) do
{
scope: 'created-by-me',
@@ -77,54 +77,89 @@ describe IssuablesHelper do
}.with_indifferent_access
end
+ let(:issues_finder) { IssuesFinder.new(nil, params) }
+ let(:merge_requests_finder) { MergeRequestsFinder.new(nil, params) }
+
+ before do
+ allow(helper).to receive(:issues_finder).and_return(issues_finder)
+ allow(helper).to receive(:merge_requests_finder).and_return(merge_requests_finder)
+ end
+
it 'returns the cached value when called for the same issuable type & with the same params' do
- expect(helper).to receive(:params).twice.and_return(params)
- expect(helper).to receive(:issuables_count_for_state).with(:issues, :opened).and_return(42)
+ expect(issues_finder).to receive(:count_by_state).and_return(opened: 42)
expect(helper.issuables_state_counter_text(:issues, :opened))
.to eq('<span>Open</span> <span class="badge">42</span>')
- expect(helper).not_to receive(:issuables_count_for_state)
+ expect(issues_finder).not_to receive(:count_by_state)
expect(helper.issuables_state_counter_text(:issues, :opened))
.to eq('<span>Open</span> <span class="badge">42</span>')
end
+ it 'takes confidential status into account when searching for issues' do
+ expect(issues_finder).to receive(:count_by_state).and_return(opened: 42)
+
+ expect(helper.issuables_state_counter_text(:issues, :opened))
+ .to include('42')
+
+ expect(issues_finder).to receive(:user_cannot_see_confidential_issues?).twice.and_return(false)
+ expect(issues_finder).to receive(:count_by_state).and_return(opened: 40)
+
+ expect(helper.issuables_state_counter_text(:issues, :opened))
+ .to include('40')
+
+ expect(issues_finder).to receive(:user_can_see_all_confidential_issues?).and_return(true)
+ expect(issues_finder).to receive(:count_by_state).and_return(opened: 45)
+
+ expect(helper.issuables_state_counter_text(:issues, :opened))
+ .to include('45')
+ end
+
+ it 'does not take confidential status into account when searching for merge requests' do
+ expect(merge_requests_finder).to receive(:count_by_state).and_return(opened: 42)
+ expect(merge_requests_finder).not_to receive(:user_cannot_see_confidential_issues?)
+ expect(merge_requests_finder).not_to receive(:user_can_see_all_confidential_issues?)
+
+ expect(helper.issuables_state_counter_text(:merge_requests, :opened))
+ .to include('42')
+ end
+
it 'does not take some keys into account in the cache key' do
- expect(helper).to receive(:params).and_return({
+ expect(issues_finder).to receive(:count_by_state).and_return(opened: 42)
+ expect(issues_finder).to receive(:params).and_return({
author_id: '11',
state: 'foo',
sort: 'foo',
utf8: 'foo',
page: 'foo'
}.with_indifferent_access)
- expect(helper).to receive(:issuables_count_for_state).with(:issues, :opened).and_return(42)
expect(helper.issuables_state_counter_text(:issues, :opened))
.to eq('<span>Open</span> <span class="badge">42</span>')
- expect(helper).to receive(:params).and_return({
+ expect(issues_finder).not_to receive(:count_by_state)
+ expect(issues_finder).to receive(:params).and_return({
author_id: '11',
state: 'bar',
sort: 'bar',
utf8: 'bar',
page: 'bar'
}.with_indifferent_access)
- expect(helper).not_to receive(:issuables_count_for_state)
expect(helper.issuables_state_counter_text(:issues, :opened))
.to eq('<span>Open</span> <span class="badge">42</span>')
end
it 'does not take params order into account in the cache key' do
- expect(helper).to receive(:params).and_return('author_id' => '11', 'state' => 'opened')
- expect(helper).to receive(:issuables_count_for_state).with(:issues, :opened).and_return(42)
+ expect(issues_finder).to receive(:params).and_return('author_id' => '11', 'state' => 'opened')
+ expect(issues_finder).to receive(:count_by_state).and_return(opened: 42)
expect(helper.issuables_state_counter_text(:issues, :opened))
.to eq('<span>Open</span> <span class="badge">42</span>')
- expect(helper).to receive(:params).and_return('state' => 'opened', 'author_id' => '11')
- expect(helper).not_to receive(:issuables_count_for_state)
+ expect(issues_finder).to receive(:params).and_return('state' => 'opened', 'author_id' => '11')
+ expect(issues_finder).not_to receive(:count_by_state)
expect(helper.issuables_state_counter_text(:issues, :opened))
.to eq('<span>Open</span> <span class="badge">42</span>')
@@ -209,5 +244,25 @@ describe IssuablesHelper do
it { expect(helper.updated_at_by(unedited_issuable)).to eq({}) }
it { expect(helper.updated_at_by(edited_issuable)).to eq(edited_updated_at_by) }
+
+ context 'when updated by a deleted user' do
+ let(:edited_updated_at_by) do
+ {
+ updatedAt: edited_issuable.updated_at.to_time.iso8601,
+ updatedBy: {
+ name: User.ghost.name,
+ path: user_path(User.ghost)
+ }
+ }
+ end
+
+ before do
+ user.destroy
+ end
+
+ it 'returns "Ghost user" as edited_by' do
+ expect(helper.updated_at_by(edited_issuable.reload)).to eq(edited_updated_at_by)
+ end
+ end
end
end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 00db98fd9d2..9524a101e74 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -8,7 +8,7 @@ describe IssuesHelper do
describe "url_for_issue" do
let(:issues_url) { ext_project.external_issue_tracker.issues_url}
let(:ext_expected) { issues_url.gsub(':id', issue.iid.to_s).gsub(':project_id', ext_project.id.to_s) }
- let(:int_expected) { polymorphic_path([@project.namespace, project, issue]) }
+ let(:int_expected) { polymorphic_path([@project.namespace, @project, issue]) }
it "returns internal path if used internal tracker" do
@project = project
@@ -22,6 +22,12 @@ describe IssuesHelper do
expect(url_for_issue(issue.iid)).to match(ext_expected)
end
+ it "returns path to internal issue when internal option passed" do
+ @project = ext_project
+
+ expect(url_for_issue(issue.iid, ext_project, internal: true)).to match(int_expected)
+ end
+
it "returns empty string if project nil" do
@project = nil
@@ -137,7 +143,7 @@ describe IssuesHelper do
let(:merge_request) { create(:merge_request) }
it "links just the merge request" do
- expected_path = namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ expected_path = project_merge_request_path(merge_request.project, merge_request)
expect(link_to_discussions_to_resolve(merge_request, nil)).to include(expected_path)
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index b4226f96a04..4b6a351cf70 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -25,17 +25,17 @@ describe MarkupHelper do
let(:actual) { "#{merge_request.to_reference} -> #{commit.to_reference} -> #{issue.to_reference}" }
it "links to the merge request" do
- expected = namespace_project_merge_request_path(project.namespace, project, merge_request)
+ expected = project_merge_request_path(project, merge_request)
expect(helper.markdown(actual)).to match(expected)
end
it "links to the commit" do
- expected = namespace_project_commit_path(project.namespace, project, commit)
+ expected = project_commit_path(project, commit)
expect(helper.markdown(actual)).to match(expected)
end
it "links to the issue" do
- expected = namespace_project_issue_path(project.namespace, project, issue)
+ expected = project_issue_path(project, issue)
expect(helper.markdown(actual)).to match(expected)
end
end
@@ -46,7 +46,7 @@ describe MarkupHelper do
let(:second_issue) { create(:issue, project: second_project) }
it 'links to the issue' do
- expected = namespace_project_issue_path(second_project.namespace, second_project, second_issue)
+ expected = project_issue_path(second_project, second_issue)
expect(markdown(actual, project: second_project)).to match(expected)
end
end
@@ -69,7 +69,7 @@ describe MarkupHelper do
# First issue link
expect(doc.css('a')[1].attr('href'))
- .to eq namespace_project_issue_path(project.namespace, project, issues[0])
+ .to eq project_issue_path(project, issues[0])
expect(doc.css('a')[1].text).to eq issues[0].to_reference
# Internal commit link
@@ -78,7 +78,7 @@ describe MarkupHelper do
# Second issue link
expect(doc.css('a')[3].attr('href'))
- .to eq namespace_project_issue_path(project.namespace, project, issues[1])
+ .to eq project_issue_path(project, issues[1])
expect(doc.css('a')[3].text).to eq issues[1].to_reference
# Trailing commit link
diff --git a/spec/helpers/milestones_helper_spec.rb b/spec/helpers/milestones_helper_spec.rb
index 3cb809d42b5..b8f9c02a486 100644
--- a/spec/helpers/milestones_helper_spec.rb
+++ b/spec/helpers/milestones_helper_spec.rb
@@ -1,6 +1,42 @@
require 'spec_helper'
describe MilestonesHelper do
+ describe '#milestones_filter_dropdown_path' do
+ let(:project) { create(:empty_project) }
+ let(:project2) { create(:empty_project) }
+ let(:group) { create(:group) }
+
+ context 'when @project present' do
+ it 'returns project milestones JSON URL' do
+ assign(:project, project)
+
+ expect(helper.milestones_filter_dropdown_path).to eq(project_milestones_path(project, :json))
+ end
+ end
+
+ context 'when @target_project present' do
+ it 'returns targeted project milestones JSON URL' do
+ assign(:target_project, project2)
+
+ expect(helper.milestones_filter_dropdown_path).to eq(project_milestones_path(project2, :json))
+ end
+ end
+
+ context 'when @group present' do
+ it 'returns group milestones JSON URL' do
+ assign(:group, group)
+
+ expect(helper.milestones_filter_dropdown_path).to eq(group_milestones_path(group, :json))
+ end
+ end
+
+ context 'when neither of @project/@target_project/@group present' do
+ it 'returns dashboard milestones JSON URL' do
+ expect(helper.milestones_filter_dropdown_path).to eq(dashboard_milestones_path(:json))
+ end
+ end
+ end
+
describe "#milestone_date_range" do
def result_for(*args)
milestone_date_range(build(:milestone, *args))
diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb
index e5143a0263d..8365b3f5538 100644
--- a/spec/helpers/namespaces_helper_spec.rb
+++ b/spec/helpers/namespaces_helper_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe NamespacesHelper, type: :helper do
+describe NamespacesHelper do
let!(:admin) { create(:admin) }
let!(:admin_group) { create(:group, :private) }
let!(:user) { create(:user) }
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index cc861af8533..56f252ba273 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -53,7 +53,7 @@ describe NotesHelper do
let(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
it 'returns the diff path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(diffs_project_merge_request_path(project, merge_request, anchor: discussion.line_code))
end
end
@@ -77,7 +77,7 @@ describe NotesHelper do
end
it 'returns the diff version path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, diff_id: merge_request_diff1, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(diffs_project_merge_request_path(project, merge_request, diff_id: merge_request_diff1, anchor: discussion.line_code))
end
end
@@ -101,7 +101,7 @@ describe NotesHelper do
end
it 'returns the diff version comparison path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, diff_id: merge_request_diff3, start_sha: merge_request_diff1.head_commit_sha, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(diffs_project_merge_request_path(project, merge_request, diff_id: merge_request_diff3, start_sha: merge_request_diff1.head_commit_sha, anchor: discussion.line_code))
end
end
@@ -129,7 +129,7 @@ describe NotesHelper do
end
it 'returns the diff path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(diffs_namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(diffs_project_merge_request_path(project, merge_request, anchor: discussion.line_code))
end
end
@@ -160,7 +160,7 @@ describe NotesHelper do
let(:discussion) { create(:diff_note_on_commit, project: project).to_discussion }
it 'returns the commit path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(namespace_project_commit_path(project.namespace, project, commit, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit, anchor: discussion.line_code))
end
end
@@ -168,7 +168,7 @@ describe NotesHelper do
let(:discussion) { create(:legacy_diff_note_on_commit, project: project).to_discussion }
it 'returns the commit path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(namespace_project_commit_path(project.namespace, project, commit, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit, anchor: discussion.line_code))
end
end
@@ -176,7 +176,7 @@ describe NotesHelper do
let(:discussion) { create(:discussion_note_on_commit, project: project).to_discussion }
it 'returns the commit path' do
- expect(helper.discussion_path(discussion)).to eq(namespace_project_commit_path(project.namespace, project, commit))
+ expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit))
end
end
end
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index 95b4032616e..9aca3987657 100644
--- a/spec/helpers/page_layout_helper_spec.rb
+++ b/spec/helpers/page_layout_helper_spec.rb
@@ -60,7 +60,7 @@ describe PageLayoutHelper do
%w(project user group).each do |type|
context "with @#{type} assigned" do
it "uses #{type.titlecase} avatar if available" do
- object = double(avatar_url: 'http://example.com/uploads/system/avatar.png')
+ object = double(avatar_url: 'http://example.com/uploads/-/system/avatar.png')
assign(type, object)
expect(helper.page_image).to eq object.avatar_url
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 9a4086725d2..45066a60f50 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -63,7 +63,7 @@ describe ProjectsHelper do
end
end
- describe "#project_list_cache_key", redis: true do
+ describe "#project_list_cache_key", clean_gitlab_redis_shared_state: true do
let(:project) { create(:project) }
it "includes the route" do
@@ -115,6 +115,82 @@ describe ProjectsHelper do
end
end
+ describe '#show_no_ssh_key_message?' do
+ let(:user) { create(:user) }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'user has no keys' do
+ it 'returns true' do
+ expect(helper.show_no_ssh_key_message?).to be_truthy
+ end
+ end
+
+ context 'user has an ssh key' do
+ it 'returns false' do
+ create(:personal_key, user: user)
+
+ expect(helper.show_no_ssh_key_message?).to be_falsey
+ end
+ end
+ end
+
+ describe '#show_no_password_message?' do
+ let(:user) { create(:user) }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'user has password set' do
+ it 'returns false' do
+ expect(helper.show_no_password_message?).to be_falsey
+ end
+ end
+
+ context 'user requires a password' do
+ let(:user) { create(:user, password_automatically_set: true) }
+
+ it 'returns true' do
+ expect(helper.show_no_password_message?).to be_truthy
+ end
+ end
+
+ context 'user requires a personal access token' do
+ it 'returns true' do
+ stub_application_setting(password_authentication_enabled?: false)
+
+ expect(helper.show_no_password_message?).to be_truthy
+ end
+ end
+ end
+
+ describe '#link_to_set_password' do
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'user requires a password' do
+ let(:user) { create(:user, password_automatically_set: true) }
+
+ it 'returns link to set a password' do
+ expect(helper.link_to_set_password).to match %r{<a href="#{edit_profile_password_path}">set a password</a>}
+ end
+ end
+
+ context 'user requires a personal access token' do
+ let(:user) { create(:user) }
+
+ it 'returns link to create a personal access token' do
+ stub_application_setting(password_authentication_enabled?: false)
+
+ expect(helper.link_to_set_password).to match %r{<a href="#{profile_personal_access_tokens_path}">create a personal access token</a>}
+ end
+ end
+ end
+
describe 'link_to_member' do
let(:group) { create(:group) }
let(:project) { create(:empty_project, group: group) }
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index cb727430117..9e561d0f191 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -170,6 +170,11 @@ describe SubmoduleHelper do
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
end
+ it 'with trailing whitespace' do
+ result = relative_self_links('../test.git ', commit_id)
+ expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
+ end
+
it 'two levels down' do
result = relative_self_links('../../test.git', commit_id)
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb
index 374517fec37..0877770c167 100644
--- a/spec/initializers/6_validations_spec.rb
+++ b/spec/initializers/6_validations_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require_relative '../../config/initializers/6_validations.rb'
-describe '6_validations', lib: true do
+describe '6_validations' do
before :all do
FileUtils.mkdir_p('tmp/tests/paths/a/b/c/d')
FileUtils.mkdir_p('tmp/tests/paths/a/b/c2')
diff --git a/spec/initializers/8_metrics_spec.rb b/spec/initializers/8_metrics_spec.rb
index a507d7f7f2b..4e6052a9f80 100644
--- a/spec/initializers/8_metrics_spec.rb
+++ b/spec/initializers/8_metrics_spec.rb
@@ -1,17 +1,25 @@
require 'spec_helper'
-require_relative '../../config/initializers/8_metrics'
-describe 'instrument_classes', lib: true do
+describe 'instrument_classes' do
let(:config) { double(:config) }
+ let(:unicorn_sampler) { double(:unicorn_sampler) }
+ let(:influx_sampler) { double(:influx_sampler) }
+
before do
allow(config).to receive(:instrument_method)
allow(config).to receive(:instrument_methods)
allow(config).to receive(:instrument_instance_method)
allow(config).to receive(:instrument_instance_methods)
+ allow(Gitlab::Metrics::UnicornSampler).to receive(:initialize_instance).and_return(unicorn_sampler)
+ allow(Gitlab::Metrics::InfluxSampler).to receive(:initialize_instance).and_return(influx_sampler)
+ allow(unicorn_sampler).to receive(:start)
+ allow(influx_sampler).to receive(:start)
+ allow(Gitlab::Application).to receive(:configure)
end
it 'can autoload and instrument all files' do
+ require_relative '../../config/initializers/8_metrics'
expect { instrument_classes(config) }.not_to raise_error
end
end
diff --git a/spec/initializers/secret_token_spec.rb b/spec/initializers/secret_token_spec.rb
index 65c97da2efd..84ad55e9f98 100644
--- a/spec/initializers/secret_token_spec.rb
+++ b/spec/initializers/secret_token_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require_relative '../../config/initializers/secret_token'
-describe 'create_tokens', lib: true do
+describe 'create_tokens' do
include StubENV
let(:secrets) { ActiveSupport::OrderedOptions.new }
diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb
index 47b4e431823..ebdabcf93f1 100644
--- a/spec/initializers/settings_spec.rb
+++ b/spec/initializers/settings_spec.rb
@@ -1,41 +1,41 @@
require 'spec_helper'
require_relative '../../config/initializers/1_settings'
-describe Settings, lib: true do
+describe Settings do
describe '#host_without_www' do
context 'URL with protocol' do
it 'returns the host' do
- expect(Settings.host_without_www('http://foo.com')).to eq 'foo.com'
- expect(Settings.host_without_www('http://www.foo.com')).to eq 'foo.com'
- expect(Settings.host_without_www('http://secure.foo.com')).to eq 'secure.foo.com'
- expect(Settings.host_without_www('http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
+ expect(described_class.host_without_www('http://foo.com')).to eq 'foo.com'
+ expect(described_class.host_without_www('http://www.foo.com')).to eq 'foo.com'
+ expect(described_class.host_without_www('http://secure.foo.com')).to eq 'secure.foo.com'
+ expect(described_class.host_without_www('http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
- expect(Settings.host_without_www('https://foo.com')).to eq 'foo.com'
- expect(Settings.host_without_www('https://www.foo.com')).to eq 'foo.com'
- expect(Settings.host_without_www('https://secure.foo.com')).to eq 'secure.foo.com'
- expect(Settings.host_without_www('https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'secure.gravatar.com'
+ expect(described_class.host_without_www('https://foo.com')).to eq 'foo.com'
+ expect(described_class.host_without_www('https://www.foo.com')).to eq 'foo.com'
+ expect(described_class.host_without_www('https://secure.foo.com')).to eq 'secure.foo.com'
+ expect(described_class.host_without_www('https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'secure.gravatar.com'
end
end
context 'URL without protocol' do
it 'returns the host' do
- expect(Settings.host_without_www('foo.com')).to eq 'foo.com'
- expect(Settings.host_without_www('www.foo.com')).to eq 'foo.com'
- expect(Settings.host_without_www('secure.foo.com')).to eq 'secure.foo.com'
- expect(Settings.host_without_www('www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
+ expect(described_class.host_without_www('foo.com')).to eq 'foo.com'
+ expect(described_class.host_without_www('www.foo.com')).to eq 'foo.com'
+ expect(described_class.host_without_www('secure.foo.com')).to eq 'secure.foo.com'
+ expect(described_class.host_without_www('www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
end
context 'URL with user/port' do
it 'returns the host' do
- expect(Settings.host_without_www('bob:pass@foo.com:8080')).to eq 'foo.com'
- expect(Settings.host_without_www('bob:pass@www.foo.com:8080')).to eq 'foo.com'
- expect(Settings.host_without_www('bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com'
- expect(Settings.host_without_www('bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
+ expect(described_class.host_without_www('bob:pass@foo.com:8080')).to eq 'foo.com'
+ expect(described_class.host_without_www('bob:pass@www.foo.com:8080')).to eq 'foo.com'
+ expect(described_class.host_without_www('bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com'
+ expect(described_class.host_without_www('bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
- expect(Settings.host_without_www('http://bob:pass@foo.com:8080')).to eq 'foo.com'
- expect(Settings.host_without_www('http://bob:pass@www.foo.com:8080')).to eq 'foo.com'
- expect(Settings.host_without_www('http://bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com'
- expect(Settings.host_without_www('http://bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
+ expect(described_class.host_without_www('http://bob:pass@foo.com:8080')).to eq 'foo.com'
+ expect(described_class.host_without_www('http://bob:pass@www.foo.com:8080')).to eq 'foo.com'
+ expect(described_class.host_without_www('http://bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com'
+ expect(described_class.host_without_www('http://bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com'
end
end
end
diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb
index 70a18f31744..02a9446ad7b 100644
--- a/spec/initializers/trusted_proxies_spec.rb
+++ b/spec/initializers/trusted_proxies_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'trusted_proxies', lib: true do
+describe 'trusted_proxies' do
context 'with default config' do
before do
set_trusted_proxies([])
diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js
index 3fc03324d16..8e056882108 100644
--- a/spec/javascripts/awards_handler_spec.js
+++ b/spec/javascripts/awards_handler_spec.js
@@ -1,7 +1,7 @@
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */
import Cookies from 'js-cookie';
-import AwardsHandler from '~/awards_handler';
+import loadAwardsHandler from '~/awards_handler';
import '~/lib/utils/common_utils';
@@ -26,14 +26,13 @@ import '~/lib/utils/common_utils';
describe('AwardsHandler', function() {
preloadFixtures('issues/issue_with_comment.html.raw');
- beforeEach(function() {
+ beforeEach(function(done) {
loadFixtures('issues/issue_with_comment.html.raw');
- awardsHandler = new AwardsHandler;
- spyOn(awardsHandler, 'postEmoji').and.callFake((function(_this) {
- return function(button, url, emoji, cb) {
- return cb();
- };
- })(this));
+ loadAwardsHandler(true).then((obj) => {
+ awardsHandler = obj;
+ spyOn(awardsHandler, 'postEmoji').and.callFake((button, url, emoji, cb) => cb());
+ done();
+ }).catch(fail);
let isEmojiMenuBuilt = false;
openAndWaitForEmojiMenu = function() {
diff --git a/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js b/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
index 1ed96a67478..ec2c549e032 100644
--- a/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
+++ b/spec/javascripts/behaviors/gl_emoji/unicode_support_map_spec.js
@@ -1,4 +1,4 @@
-import { getUnicodeSupportMap } from '~/behaviors/gl_emoji/unicode_support_map';
+import getUnicodeSupportMap from '~/emoji/support/unicode_support_map';
import AccessorUtilities from '~/lib/utils/accessor';
describe('Unicode Support Map', () => {
diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js
index f56b99f8a16..6dc48f9a293 100644
--- a/spec/javascripts/behaviors/quick_submit_spec.js
+++ b/spec/javascripts/behaviors/quick_submit_spec.js
@@ -40,16 +40,29 @@ import '~/behaviors/quick_submit';
it('disables input of type submit', function() {
const submitButton = $('.js-quick-submit input[type=submit]');
this.textarea.trigger(keydownEvent());
+
expect(submitButton).toBeDisabled();
});
it('disables button of type submit', function() {
- // button doesn't exist in fixture, add it manually
- const submitButton = $('<button type="submit">Submit it</button>');
- submitButton.insertAfter(this.textarea);
-
+ const submitButton = $('.js-quick-submit input[type=submit]');
this.textarea.trigger(keydownEvent());
+
expect(submitButton).toBeDisabled();
});
+ it('only clicks one submit', function() {
+ const existingSubmit = $('.js-quick-submit input[type=submit]');
+ // Add an extra submit button
+ const newSubmit = $('<button type="submit">Submit it</button>');
+ newSubmit.insertAfter(this.textarea);
+
+ const oldClick = spyOnEvent(existingSubmit, 'click');
+ const newClick = spyOnEvent(newSubmit, 'click');
+
+ this.textarea.trigger(keydownEvent());
+
+ expect(oldClick).not.toHaveBeenTriggered();
+ expect(newClick).toHaveBeenTriggered();
+ });
// We cannot stub `navigator.userAgent` for CI's `rake karma` task, so we'll
// only run the tests that apply to the current platform
if (navigator.userAgent.match(/Macintosh/)) {
diff --git a/spec/javascripts/boards/board_new_issue_spec.js b/spec/javascripts/boards/board_new_issue_spec.js
index 832877de71c..c0a7323a505 100644
--- a/spec/javascripts/boards/board_new_issue_spec.js
+++ b/spec/javascripts/boards/board_new_issue_spec.js
@@ -12,6 +12,7 @@ import './mock_data';
describe('Issue boards new issue form', () => {
let vm;
let list;
+ let newIssueMock;
const promiseReturn = {
json() {
return {
@@ -21,7 +22,11 @@ describe('Issue boards new issue form', () => {
};
const submitIssue = () => {
- vm.$el.querySelector('.btn-success').click();
+ const dummySubmitEvent = {
+ preventDefault() {},
+ };
+ vm.$refs.submitButton = vm.$el.querySelector('.btn-success');
+ return vm.submit(dummySubmitEvent);
};
beforeEach((done) => {
@@ -32,29 +37,35 @@ describe('Issue boards new issue form', () => {
gl.issueBoards.BoardsStore.create();
gl.IssueBoardsApp = new Vue();
- setTimeout(() => {
- list = new List(listObj);
-
- spyOn(gl.boardService, 'newIssue').and.callFake(() => new Promise((resolve, reject) => {
- if (vm.title === 'error') {
- reject();
- } else {
- resolve(promiseReturn);
- }
- }));
-
- vm = new BoardNewIssueComp({
- propsData: {
- list,
- },
- }).$mount();
-
- done();
- }, 0);
+ list = new List(listObj);
+
+ newIssueMock = Promise.resolve(promiseReturn);
+ spyOn(list, 'newIssue').and.callFake(() => newIssueMock);
+
+ vm = new BoardNewIssueComp({
+ propsData: {
+ list,
+ },
+ }).$mount();
+
+ Vue.nextTick()
+ .then(done)
+ .catch(done.fail);
});
- afterEach(() => {
- Vue.http.interceptors = _.without(Vue.http.interceptors, boardsMockInterceptor);
+ it('calls submit if submit button is clicked', (done) => {
+ spyOn(vm, 'submit');
+ vm.title = 'Testing Title';
+
+ Vue.nextTick()
+ .then(() => {
+ vm.$el.querySelector('.btn-success').click();
+
+ expect(vm.submit.calls.count()).toBe(1);
+ expect(vm.$refs['submit-button']).toBe(vm.$el.querySelector('.btn-success'));
+ })
+ .then(done)
+ .catch(done.fail);
});
it('disables submit button if title is empty', () => {
@@ -64,136 +75,122 @@ describe('Issue boards new issue form', () => {
it('enables submit button if title is not empty', (done) => {
vm.title = 'Testing Title';
- setTimeout(() => {
- expect(vm.$el.querySelector('.form-control').value).toBe('Testing Title');
- expect(vm.$el.querySelector('.btn-success').disabled).not.toBe(true);
-
- done();
- }, 0);
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.form-control').value).toBe('Testing Title');
+ expect(vm.$el.querySelector('.btn-success').disabled).not.toBe(true);
+ })
+ .then(done)
+ .catch(done.fail);
});
it('clears title after clicking cancel', (done) => {
vm.$el.querySelector('.btn-default').click();
- setTimeout(() => {
- expect(vm.title).toBe('');
- done();
- }, 0);
+ Vue.nextTick()
+ .then(() => {
+ expect(vm.title).toBe('');
+ })
+ .then(done)
+ .catch(done.fail);
});
it('does not create new issue if title is empty', (done) => {
- submitIssue();
-
- setTimeout(() => {
- expect(gl.boardService.newIssue).not.toHaveBeenCalled();
- done();
- }, 0);
+ submitIssue()
+ .then(() => {
+ expect(list.newIssue).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
});
describe('submit success', () => {
it('creates new issue', (done) => {
vm.title = 'submit title';
- setTimeout(() => {
- submitIssue();
-
- expect(gl.boardService.newIssue).toHaveBeenCalled();
- done();
- }, 0);
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(list.newIssue).toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
});
it('enables button after submit', (done) => {
vm.title = 'submit issue';
- setTimeout(() => {
- submitIssue();
-
- expect(vm.$el.querySelector('.btn-success').disabled).toBe(false);
- done();
- }, 0);
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
+ expect(vm.$el.querySelector('.btn-success').disabled).toBe(false);
+ })
+ .then(done)
+ .catch(done.fail);
});
it('clears title after submit', (done) => {
vm.title = 'submit issue';
- Vue.nextTick(() => {
- submitIssue();
-
- setTimeout(() => {
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
expect(vm.title).toBe('');
- done();
- }, 0);
- });
- });
-
- it('adds new issue to top of list after submit request', (done) => {
- vm.title = 'submit issue';
-
- setTimeout(() => {
- submitIssue();
-
- setTimeout(() => {
- expect(list.issues.length).toBe(2);
- expect(list.issues[0].title).toBe('submit issue');
- expect(list.issues[0].subscribed).toBe(true);
- done();
- }, 0);
- }, 0);
+ })
+ .then(done)
+ .catch(done.fail);
});
it('sets detail issue after submit', (done) => {
expect(gl.issueBoards.BoardsStore.detail.issue.title).toBe(undefined);
vm.title = 'submit issue';
- setTimeout(() => {
- submitIssue();
-
- setTimeout(() => {
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
expect(gl.issueBoards.BoardsStore.detail.issue.title).toBe('submit issue');
- done();
- }, 0);
- }, 0);
+ })
+ .then(done)
+ .catch(done.fail);
});
it('sets detail list after submit', (done) => {
vm.title = 'submit issue';
- setTimeout(() => {
- submitIssue();
-
- setTimeout(() => {
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
expect(gl.issueBoards.BoardsStore.detail.list.id).toBe(list.id);
- done();
- }, 0);
- }, 0);
+ })
+ .then(done)
+ .catch(done.fail);
});
});
describe('submit error', () => {
- it('removes issue', (done) => {
+ beforeEach(() => {
+ newIssueMock = Promise.reject(new Error('My hovercraft is full of eels!'));
vm.title = 'error';
+ });
- setTimeout(() => {
- submitIssue();
-
- setTimeout(() => {
+ it('removes issue', (done) => {
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
expect(list.issues.length).toBe(1);
- done();
- }, 0);
- }, 0);
+ })
+ .then(done)
+ .catch(done.fail);
});
it('shows error', (done) => {
- vm.title = 'error';
-
- setTimeout(() => {
- submitIssue();
-
- setTimeout(() => {
+ Vue.nextTick()
+ .then(submitIssue)
+ .then(() => {
expect(vm.error).toBe(true);
- done();
- }, 0);
- }, 0);
+ })
+ .then(done)
+ .catch(done.fail);
});
});
});
diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js
index 8e3d9fd77a0..db50829a276 100644
--- a/spec/javascripts/boards/list_spec.js
+++ b/spec/javascripts/boards/list_spec.js
@@ -150,4 +150,41 @@ describe('List model', () => {
expect(list.getIssues).toHaveBeenCalled();
});
});
+
+ describe('newIssue', () => {
+ beforeEach(() => {
+ spyOn(gl.boardService, 'newIssue').and.returnValue(Promise.resolve({
+ json() {
+ return {
+ iid: 42,
+ };
+ },
+ }));
+ });
+
+ it('adds new issue to top of list', (done) => {
+ list.issues.push(new ListIssue({
+ title: 'Testing',
+ iid: _.random(10000),
+ confidential: false,
+ labels: [list.label],
+ assignees: [],
+ }));
+ const dummyIssue = new ListIssue({
+ title: 'new issue',
+ iid: _.random(10000),
+ confidential: false,
+ labels: [list.label],
+ assignees: [],
+ });
+
+ list.newIssue(dummyIssue)
+ .then(() => {
+ expect(list.issues.length).toBe(2);
+ expect(list.issues[0]).toBe(dummyIssue);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
});
diff --git a/spec/javascripts/close_reopen_report_toggle_spec.js b/spec/javascripts/close_reopen_report_toggle_spec.js
new file mode 100644
index 00000000000..925e959c85a
--- /dev/null
+++ b/spec/javascripts/close_reopen_report_toggle_spec.js
@@ -0,0 +1,270 @@
+import CloseReopenReportToggle from '~/close_reopen_report_toggle';
+import DropLab from '~/droplab/drop_lab';
+
+describe('CloseReopenReportToggle', () => {
+ describe('class constructor', () => {
+ const dropdownTrigger = {};
+ const dropdownList = {};
+ const button = {};
+ let commentTypeToggle;
+
+ beforeEach(function () {
+ commentTypeToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+ });
+
+ it('sets .dropdownTrigger', function () {
+ expect(commentTypeToggle.dropdownTrigger).toBe(dropdownTrigger);
+ });
+
+ it('sets .dropdownList', function () {
+ expect(commentTypeToggle.dropdownList).toBe(dropdownList);
+ });
+
+ it('sets .button', function () {
+ expect(commentTypeToggle.button).toBe(button);
+ });
+ });
+
+ describe('initDroplab', () => {
+ let closeReopenReportToggle;
+ const dropdownList = jasmine.createSpyObj('dropdownList', ['querySelector']);
+ const dropdownTrigger = {};
+ const button = {};
+ const reopenItem = {};
+ const closeItem = {};
+ const config = {};
+
+ beforeEach(() => {
+ spyOn(DropLab.prototype, 'init');
+ dropdownList.querySelector.and.returnValues(reopenItem, closeItem);
+
+ closeReopenReportToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+
+ spyOn(closeReopenReportToggle, 'setConfig').and.returnValue(config);
+
+ closeReopenReportToggle.initDroplab();
+ });
+
+ it('sets .reopenItem and .closeItem', () => {
+ expect(dropdownList.querySelector).toHaveBeenCalledWith('.reopen-item');
+ expect(dropdownList.querySelector).toHaveBeenCalledWith('.close-item');
+ expect(closeReopenReportToggle.reopenItem).toBe(reopenItem);
+ expect(closeReopenReportToggle.closeItem).toBe(closeItem);
+ });
+
+ it('sets .droplab', () => {
+ expect(closeReopenReportToggle.droplab).toEqual(jasmine.any(Object));
+ });
+
+ it('calls .setConfig', () => {
+ expect(closeReopenReportToggle.setConfig).toHaveBeenCalled();
+ });
+
+ it('calls droplab.init', () => {
+ expect(DropLab.prototype.init).toHaveBeenCalledWith(
+ dropdownTrigger,
+ dropdownList,
+ jasmine.any(Array),
+ config,
+ );
+ });
+ });
+
+ describe('updateButton', () => {
+ let closeReopenReportToggle;
+ const dropdownList = {};
+ const dropdownTrigger = {};
+ const button = jasmine.createSpyObj('button', ['blur']);
+ const isClosed = true;
+
+ beforeEach(() => {
+ closeReopenReportToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+
+ spyOn(closeReopenReportToggle, 'toggleButtonType');
+
+ closeReopenReportToggle.updateButton(isClosed);
+ });
+
+ it('calls .toggleButtonType', () => {
+ expect(closeReopenReportToggle.toggleButtonType).toHaveBeenCalledWith(isClosed);
+ });
+
+ it('calls .button.blur', () => {
+ expect(closeReopenReportToggle.button.blur).toHaveBeenCalled();
+ });
+ });
+
+ describe('toggleButtonType', () => {
+ let closeReopenReportToggle;
+ const dropdownList = {};
+ const dropdownTrigger = {};
+ const button = {};
+ const isClosed = true;
+ const showItem = jasmine.createSpyObj('showItem', ['click']);
+ const hideItem = {};
+ showItem.classList = jasmine.createSpyObj('classList', ['add', 'remove']);
+ hideItem.classList = jasmine.createSpyObj('classList', ['add', 'remove']);
+
+ beforeEach(() => {
+ closeReopenReportToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+
+ spyOn(closeReopenReportToggle, 'getButtonTypes').and.returnValue([showItem, hideItem]);
+
+ closeReopenReportToggle.toggleButtonType(isClosed);
+ });
+
+ it('calls .getButtonTypes', () => {
+ expect(closeReopenReportToggle.getButtonTypes).toHaveBeenCalledWith(isClosed);
+ });
+
+ it('removes hide class and add selected class to showItem, opposite for hideItem', () => {
+ expect(showItem.classList.remove).toHaveBeenCalledWith('hidden');
+ expect(showItem.classList.add).toHaveBeenCalledWith('droplab-item-selected');
+ expect(hideItem.classList.add).toHaveBeenCalledWith('hidden');
+ expect(hideItem.classList.remove).toHaveBeenCalledWith('droplab-item-selected');
+ });
+
+ it('clicks the showItem', () => {
+ expect(showItem.click).toHaveBeenCalled();
+ });
+ });
+
+ describe('getButtonTypes', () => {
+ let closeReopenReportToggle;
+ const dropdownList = {};
+ const dropdownTrigger = {};
+ const button = {};
+ const reopenItem = {};
+ const closeItem = {};
+
+ beforeEach(() => {
+ closeReopenReportToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+
+ closeReopenReportToggle.reopenItem = reopenItem;
+ closeReopenReportToggle.closeItem = closeItem;
+ });
+
+ it('returns reopenItem, closeItem if isClosed is true', () => {
+ const buttonTypes = closeReopenReportToggle.getButtonTypes(true);
+
+ expect(buttonTypes).toEqual([reopenItem, closeItem]);
+ });
+
+ it('returns closeItem, reopenItem if isClosed is false', () => {
+ const buttonTypes = closeReopenReportToggle.getButtonTypes(false);
+
+ expect(buttonTypes).toEqual([closeItem, reopenItem]);
+ });
+ });
+
+ describe('setDisable', () => {
+ let closeReopenReportToggle;
+ const dropdownList = {};
+ const dropdownTrigger = jasmine.createSpyObj('button', ['setAttribute', 'removeAttribute']);
+ const button = jasmine.createSpyObj('button', ['setAttribute', 'removeAttribute']);
+
+ beforeEach(() => {
+ closeReopenReportToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+ });
+
+ it('disable .button and .dropdownTrigger if shouldDisable is true', () => {
+ closeReopenReportToggle.setDisable(true);
+
+ expect(button.setAttribute).toHaveBeenCalledWith('disabled', 'true');
+ expect(dropdownTrigger.setAttribute).toHaveBeenCalledWith('disabled', 'true');
+ });
+
+ it('disable .button and .dropdownTrigger if shouldDisable is undefined', () => {
+ closeReopenReportToggle.setDisable();
+
+ expect(button.setAttribute).toHaveBeenCalledWith('disabled', 'true');
+ expect(dropdownTrigger.setAttribute).toHaveBeenCalledWith('disabled', 'true');
+ });
+
+ it('enable .button and .dropdownTrigger if shouldDisable is false', () => {
+ closeReopenReportToggle.setDisable(false);
+
+ expect(button.removeAttribute).toHaveBeenCalledWith('disabled');
+ expect(dropdownTrigger.removeAttribute).toHaveBeenCalledWith('disabled');
+ });
+ });
+
+ describe('setConfig', () => {
+ let closeReopenReportToggle;
+ const dropdownList = {};
+ const dropdownTrigger = {};
+ const button = {};
+ let config;
+
+ beforeEach(() => {
+ closeReopenReportToggle = new CloseReopenReportToggle({
+ dropdownTrigger,
+ dropdownList,
+ button,
+ });
+
+ config = closeReopenReportToggle.setConfig();
+ });
+
+ it('returns a config object', () => {
+ expect(config).toEqual({
+ InputSetter: [
+ {
+ input: button,
+ valueAttribute: 'data-text',
+ inputAttribute: 'data-value',
+ },
+ {
+ input: button,
+ valueAttribute: 'data-text',
+ inputAttribute: 'title',
+ },
+ {
+ input: button,
+ valueAttribute: 'data-button-class',
+ inputAttribute: 'class',
+ },
+ {
+ input: dropdownTrigger,
+ valueAttribute: 'data-toggle-class',
+ inputAttribute: 'class',
+ },
+ {
+ input: button,
+ valueAttribute: 'data-url',
+ inputAttribute: 'href',
+ },
+ {
+ input: button,
+ valueAttribute: 'data-method',
+ inputAttribute: 'data-method',
+ },
+ ],
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js
index 694f94efcff..a34cadec0ab 100644
--- a/spec/javascripts/commit/pipelines/pipelines_spec.js
+++ b/spec/javascripts/commit/pipelines/pipelines_spec.js
@@ -85,6 +85,41 @@ describe('Pipelines table in Commits and Merge requests', () => {
}, 0);
});
});
+
+ describe('pipeline badge counts', () => {
+ const pipelinesResponse = (request, next) => {
+ next(request.respondWith(JSON.stringify([pipeline]), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(pipelinesResponse);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, pipelinesResponse);
+ this.component.$destroy();
+ });
+
+ it('should receive update-pipelines-count event', (done) => {
+ const element = document.createElement('div');
+ document.body.appendChild(element);
+
+ element.addEventListener('update-pipelines-count', (event) => {
+ expect(event.detail.pipelines).toEqual([pipeline]);
+ done();
+ });
+
+ this.component = new PipelinesTable({
+ propsData: {
+ endpoint: 'endpoint',
+ helpPagePath: 'foo',
+ },
+ }).$mount();
+ element.appendChild(this.component.$el);
+ });
+ });
});
describe('unsuccessfull request', () => {
diff --git a/spec/javascripts/gl_emoji_spec.js b/spec/javascripts/emoji_spec.js
index a09e0072fa8..fa11c602ec3 100644
--- a/spec/javascripts/gl_emoji_spec.js
+++ b/spec/javascripts/emoji_spec.js
@@ -1,12 +1,11 @@
-import { glEmojiTag } from '~/behaviors/gl_emoji';
-import {
- isEmojiUnicodeSupported,
+import { glEmojiTag } from '~/emoji';
+import isEmojiUnicodeSupported, {
isFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
isPersonZwjEmoji,
-} from '~/behaviors/gl_emoji/is_emoji_unicode_supported';
+} from '~/emoji/support/is_emoji_unicode_supported';
const emptySupportMap = {
personZwj: false,
diff --git a/spec/javascripts/environments/environment_actions_spec.js b/spec/javascripts/environments/environment_actions_spec.js
index 596d812c724..ea40a1fcd4b 100644
--- a/spec/javascripts/environments/environment_actions_spec.js
+++ b/spec/javascripts/environments/environment_actions_spec.js
@@ -32,9 +32,16 @@ describe('Actions Component', () => {
}).$mount();
});
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Deploy to...');
+ });
+ });
+
it('should render a dropdown button with icon and title attribute', () => {
expect(component.$el.querySelector('.fa-caret-down')).toBeDefined();
- expect(component.$el.querySelector('.dropdown-new').getAttribute('title')).toEqual('Deploy to...');
+ expect(component.$el.querySelector('.dropdown-new').getAttribute('data-original-title')).toEqual('Deploy to...');
+ expect(component.$el.querySelector('.dropdown-new').getAttribute('aria-label')).toEqual('Deploy to...');
});
it('should render a dropdown with the provided list of actions', () => {
diff --git a/spec/javascripts/environments/environment_monitoring_spec.js b/spec/javascripts/environments/environment_monitoring_spec.js
index 0f3dba66230..f8d8223967a 100644
--- a/spec/javascripts/environments/environment_monitoring_spec.js
+++ b/spec/javascripts/environments/environment_monitoring_spec.js
@@ -3,21 +3,30 @@ import monitoringComp from '~/environments/components/environment_monitoring.vue
describe('Monitoring Component', () => {
let MonitoringComponent;
+ let component;
+
+ const monitoringUrl = 'https://gitlab.com';
beforeEach(() => {
MonitoringComponent = Vue.extend(monitoringComp);
- });
- it('should render a link to environment monitoring page', () => {
- const monitoringUrl = 'https://gitlab.com';
- const component = new MonitoringComponent({
+ component = new MonitoringComponent({
propsData: {
monitoringUrl,
},
}).$mount();
+ });
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Monitoring');
+ });
+ });
+
+ it('should render a link to environment monitoring page', () => {
expect(component.$el.getAttribute('href')).toEqual(monitoringUrl);
expect(component.$el.querySelector('.fa-area-chart')).toBeDefined();
- expect(component.$el.getAttribute('title')).toEqual('Monitoring');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Monitoring');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Monitoring');
});
});
diff --git a/spec/javascripts/environments/environment_spec.js b/spec/javascripts/environments/environment_spec.js
index 6639a6b5e7b..0c8817a8148 100644
--- a/spec/javascripts/environments/environment_spec.js
+++ b/spec/javascripts/environments/environment_spec.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import '~/flash';
import environmentsComponent from '~/environments/components/environment.vue';
import { environment, folder } from './mock_data';
+import { headersInterceptor } from '../helpers/vue_resource_helper';
describe('Environment', () => {
preloadFixtures('static/environments/environments.html.raw');
@@ -25,12 +26,14 @@ describe('Environment', () => {
beforeEach(() => {
Vue.http.interceptors.push(environmentsEmptyResponseInterceptor);
+ Vue.http.interceptors.push(headersInterceptor);
});
afterEach(() => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsEmptyResponseInterceptor,
);
+ Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
it('should render the empty state', (done) => {
@@ -54,6 +57,10 @@ describe('Environment', () => {
describe('with paginated environments', () => {
const environmentsResponseInterceptor = (request, next) => {
+ next((response) => {
+ response.headers.set('X-nExt-pAge', '2');
+ });
+
next(request.respondWith(JSON.stringify({
environments: [environment],
stopped_count: 1,
@@ -73,6 +80,7 @@ describe('Environment', () => {
beforeEach(() => {
Vue.http.interceptors.push(environmentsResponseInterceptor);
+ Vue.http.interceptors.push(headersInterceptor);
component = new EnvironmentsComponent({
el: document.querySelector('#environments-list-view'),
});
@@ -82,6 +90,7 @@ describe('Environment', () => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsResponseInterceptor,
);
+ Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
it('should render a table with environments', (done) => {
diff --git a/spec/javascripts/environments/environment_stop_spec.js b/spec/javascripts/environments/environment_stop_spec.js
index 8131f1e5b11..3f95faf466a 100644
--- a/spec/javascripts/environments/environment_stop_spec.js
+++ b/spec/javascripts/environments/environment_stop_spec.js
@@ -17,8 +17,15 @@ describe('Stop Component', () => {
}).$mount();
});
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Stop');
+ });
+ });
+
it('should render a button to stop the environment', () => {
expect(component.$el.tagName).toEqual('BUTTON');
- expect(component.$el.getAttribute('title')).toEqual('Stop');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Stop');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Stop');
});
});
diff --git a/spec/javascripts/environments/environment_terminal_button_spec.js b/spec/javascripts/environments/environment_terminal_button_spec.js
index 858472af4b6..f1576b19d1b 100644
--- a/spec/javascripts/environments/environment_terminal_button_spec.js
+++ b/spec/javascripts/environments/environment_terminal_button_spec.js
@@ -16,9 +16,16 @@ describe('Stop Component', () => {
}).$mount();
});
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Terminal');
+ });
+ });
+
it('should render a link to open a web terminal with the provided path', () => {
expect(component.$el.tagName).toEqual('A');
- expect(component.$el.getAttribute('title')).toEqual('Terminal');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Terminal');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Terminal');
expect(component.$el.getAttribute('href')).toEqual(terminalPath);
});
});
diff --git a/spec/javascripts/environments/environments_store_spec.js b/spec/javascripts/environments/environments_store_spec.js
index 6e855530b21..f2c6ec24dd7 100644
--- a/spec/javascripts/environments/environments_store_spec.js
+++ b/spec/javascripts/environments/environments_store_spec.js
@@ -86,6 +86,16 @@ describe('Store', () => {
store.toggleFolder(store.state.environments[1]);
expect(store.state.environments[1].isOpen).toEqual(false);
});
+
+ it('should keep folder open when environments are updated', () => {
+ store.storeEnvironments(serverData);
+
+ store.toggleFolder(store.state.environments[1]);
+ expect(store.state.environments[1].isOpen).toEqual(true);
+
+ store.storeEnvironments(serverData);
+ expect(store.state.environments[1].isOpen).toEqual(true);
+ });
});
describe('setfolderContent', () => {
@@ -97,6 +107,17 @@ describe('Store', () => {
expect(store.state.environments[1].children.length).toEqual(serverData.length);
expect(store.state.environments[1].children[0].isChildren).toEqual(true);
});
+
+ it('should keep folder content when environments are updated', () => {
+ store.storeEnvironments(serverData);
+
+ store.setfolderContent(store.state.environments[1], serverData);
+
+ expect(store.state.environments[1].children.length).toEqual(serverData.length);
+ // poll
+ store.storeEnvironments(serverData);
+ expect(store.state.environments[1].children.length).toEqual(serverData.length);
+ });
});
describe('store pagination', () => {
diff --git a/spec/javascripts/environments/folder/environments_folder_view_spec.js b/spec/javascripts/environments/folder/environments_folder_view_spec.js
index 350078ad5f5..fdaea5c0b0c 100644
--- a/spec/javascripts/environments/folder/environments_folder_view_spec.js
+++ b/spec/javascripts/environments/folder/environments_folder_view_spec.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import '~/flash';
import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
import { environmentsList } from '../mock_data';
+import { headersInterceptor } from '../../helpers/vue_resource_helper';
describe('Environments Folder View', () => {
preloadFixtures('static/environments/environments_folder_view.html.raw');
@@ -36,6 +37,8 @@ describe('Environments Folder View', () => {
beforeEach(() => {
Vue.http.interceptors.push(environmentsResponseInterceptor);
+ Vue.http.interceptors.push(headersInterceptor);
+
component = new EnvironmentsFolderViewComponent({
el: document.querySelector('#environments-folder-list-view'),
});
@@ -45,6 +48,7 @@ describe('Environments Folder View', () => {
Vue.http.interceptors = _.without(
Vue.http.interceptors, environmentsResponseInterceptor,
);
+ Vue.http.interceptors = _.without(Vue.http.interceptors, headersInterceptor);
});
it('should render a table with environments', (done) => {
diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js b/spec/javascripts/filtered_search/dropdown_user_spec.js
index f7708301b6e..b3c9bca64cc 100644
--- a/spec/javascripts/filtered_search/dropdown_user_spec.js
+++ b/spec/javascripts/filtered_search/dropdown_user_spec.js
@@ -12,7 +12,9 @@ describe('Dropdown User', () => {
spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {});
spyOn(gl.DropdownUtils, 'getSearchInput').and.callFake(() => {});
- dropdownUser = new gl.DropdownUser(null, null, null, gl.FilteredSearchTokenKeys);
+ dropdownUser = new gl.DropdownUser({
+ tokenKeys: gl.FilteredSearchTokenKeys,
+ });
});
it('should not return the double quote found in value', () => {
@@ -66,4 +68,41 @@ describe('Dropdown User', () => {
window.gon = {};
});
});
+
+ describe('hideCurrentUser', () => {
+ const fixtureTemplate = 'issues/issue_list.html.raw';
+ preloadFixtures(fixtureTemplate);
+
+ let dropdown;
+ let authorFilterDropdownElement;
+
+ beforeEach(() => {
+ loadFixtures(fixtureTemplate);
+ authorFilterDropdownElement = document.querySelector('#js-dropdown-author');
+ const dummyInput = document.createElement('div');
+ dropdown = new gl.DropdownUser({
+ dropdown: authorFilterDropdownElement,
+ input: dummyInput,
+ });
+ });
+
+ const findCurrentUserElement = () => authorFilterDropdownElement.querySelector('.js-current-user');
+
+ it('hides the current user from dropdown', () => {
+ const currentUserElement = findCurrentUserElement();
+ expect(currentUserElement).not.toBe(null);
+
+ dropdown.hideCurrentUser();
+
+ expect(currentUserElement.classList).toContain('hidden');
+ });
+
+ it('does nothing if no user is logged in', () => {
+ const currentUserElement = findCurrentUserElement();
+ currentUserElement.parentNode.removeChild(currentUserElement);
+ expect(findCurrentUserElement()).toBe(null);
+
+ dropdown.hideCurrentUser();
+ });
+ });
});
diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
index f67cd356ef1..16ae649ee60 100644
--- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
@@ -48,18 +48,23 @@ describe('Filtered Search Manager', () => {
</div>
`);
+ spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {});
+ });
+
+ const initializeManager = () => {
+ /* eslint-disable jasmine/no-unsafe-spy */
spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {});
spyOn(gl.FilteredSearchManager.prototype, 'tokenChange').and.callFake(() => {});
- spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {});
spyOn(gl.FilteredSearchDropdownManager.prototype, 'updateDropdownOffset').and.callFake(() => {});
spyOn(gl.utils, 'getParameterByName').and.returnValue(null);
spyOn(gl.FilteredSearchVisualTokens, 'unselectTokens').and.callThrough();
+ /* eslint-enable jasmine/no-unsafe-spy */
input = document.querySelector('.filtered-search');
tokensContainer = document.querySelector('.tokens-container');
manager = new gl.FilteredSearchManager();
manager.setup();
- });
+ };
afterEach(() => {
manager.cleanup();
@@ -67,33 +72,34 @@ describe('Filtered Search Manager', () => {
describe('class constructor', () => {
const isLocalStorageAvailable = 'isLocalStorageAvailable';
- let filteredSearchManager;
beforeEach(() => {
spyOn(RecentSearchesService, 'isAvailable').and.returnValue(isLocalStorageAvailable);
spyOn(recentSearchesStoreSrc, 'default');
spyOn(RecentSearchesRoot.prototype, 'render');
-
- filteredSearchManager = new gl.FilteredSearchManager();
- filteredSearchManager.setup();
-
- return filteredSearchManager;
});
it('should instantiate RecentSearchesStore with isLocalStorageAvailable', () => {
+ manager = new gl.FilteredSearchManager();
+
expect(RecentSearchesService.isAvailable).toHaveBeenCalled();
expect(recentSearchesStoreSrc.default).toHaveBeenCalledWith({
isLocalStorageAvailable,
allowedKeys: gl.FilteredSearchTokenKeys.getKeys(),
});
});
+ });
+
+ describe('setup', () => {
+ beforeEach(() => {
+ manager = new gl.FilteredSearchManager();
+ });
it('should not instantiate Flash if an RecentSearchesServiceError is caught', () => {
spyOn(RecentSearchesService.prototype, 'fetch').and.callFake(() => Promise.reject(new RecentSearchesServiceError()));
spyOn(window, 'Flash');
- filteredSearchManager = new gl.FilteredSearchManager();
- filteredSearchManager.setup();
+ manager.setup();
expect(window.Flash).not.toHaveBeenCalled();
});
@@ -102,10 +108,12 @@ describe('Filtered Search Manager', () => {
describe('searchState', () => {
beforeEach(() => {
spyOn(gl.FilteredSearchManager.prototype, 'search').and.callFake(() => {});
+ initializeManager();
});
it('should blur button', () => {
const e = {
+ preventDefault: () => {},
currentTarget: {
blur: () => {},
},
@@ -118,6 +126,7 @@ describe('Filtered Search Manager', () => {
it('should not call search if there is no state', () => {
const e = {
+ preventDefault: () => {},
currentTarget: {
blur: () => {},
},
@@ -129,6 +138,7 @@ describe('Filtered Search Manager', () => {
it('should call search when there is state', () => {
const e = {
+ preventDefault: () => {},
currentTarget: {
blur: () => {},
dataset: {
@@ -145,6 +155,10 @@ describe('Filtered Search Manager', () => {
describe('search', () => {
const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened';
+ beforeEach(() => {
+ initializeManager();
+ });
+
it('should search with a single word', (done) => {
input.value = 'searchTerm';
@@ -194,6 +208,10 @@ describe('Filtered Search Manager', () => {
});
describe('handleInputPlaceholder', () => {
+ beforeEach(() => {
+ initializeManager();
+ });
+
it('should render placeholder when there is no input', () => {
expect(input.placeholder).toEqual(placeholder);
});
@@ -220,6 +238,10 @@ describe('Filtered Search Manager', () => {
});
describe('checkForBackspace', () => {
+ beforeEach(() => {
+ initializeManager();
+ });
+
describe('tokens and no input', () => {
beforeEach(() => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
@@ -257,6 +279,10 @@ describe('Filtered Search Manager', () => {
});
describe('removeToken', () => {
+ beforeEach(() => {
+ initializeManager();
+ });
+
it('removes token even when it is already selected', () => {
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true),
@@ -288,6 +314,7 @@ describe('Filtered Search Manager', () => {
describe('removeSelectedTokenKeydown', () => {
beforeEach(() => {
+ initializeManager();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', 'none', true),
);
@@ -341,27 +368,39 @@ describe('Filtered Search Manager', () => {
spyOn(gl.FilteredSearchVisualTokens, 'removeSelectedToken').and.callThrough();
spyOn(gl.FilteredSearchManager.prototype, 'handleInputPlaceholder').and.callThrough();
spyOn(gl.FilteredSearchManager.prototype, 'toggleClearSearchButton').and.callThrough();
- manager.removeSelectedToken();
+ initializeManager();
});
it('calls FilteredSearchVisualTokens.removeSelectedToken', () => {
+ manager.removeSelectedToken();
+
expect(gl.FilteredSearchVisualTokens.removeSelectedToken).toHaveBeenCalled();
});
it('calls handleInputPlaceholder', () => {
+ manager.removeSelectedToken();
+
expect(manager.handleInputPlaceholder).toHaveBeenCalled();
});
it('calls toggleClearSearchButton', () => {
+ manager.removeSelectedToken();
+
expect(manager.toggleClearSearchButton).toHaveBeenCalled();
});
it('calls update dropdown offset', () => {
+ manager.removeSelectedToken();
+
expect(manager.dropdownManager.updateDropdownOffset).toHaveBeenCalled();
});
});
describe('toggleInputContainerFocus', () => {
+ beforeEach(() => {
+ initializeManager();
+ });
+
it('toggles on focus', () => {
input.focus();
expect(document.querySelector('.filtered-search-box').classList.contains('focus')).toEqual(true);
diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb
index 0715f4d5f6b..7e2f364ffa4 100644
--- a/spec/javascripts/fixtures/merge_requests.rb
+++ b/spec/javascripts/fixtures/merge_requests.rb
@@ -55,20 +55,14 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
render_merge_request(example.description, merge_request)
end
- it 'merge_requests/changes_tab_with_comments.json' do |example|
- create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
- create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
- render_merge_request(example.description, merge_request, action: :diffs, format: :json)
- end
-
private
- def render_merge_request(fixture_file_name, merge_request, action: :show, format: :html)
- get action,
+ def render_merge_request(fixture_file_name, merge_request)
+ get :show,
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.to_param,
- format: format
+ format: :html
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb
new file mode 100644
index 00000000000..ac5b06ace6d
--- /dev/null
+++ b/spec/javascripts/fixtures/merge_requests_diffs.rb
@@ -0,0 +1,57 @@
+
+require 'spec_helper'
+
+describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:admin) { create(:admin) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') }
+ let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') }
+ let(:path) { "files/ruby/popen.rb" }
+ let(:position) do
+ Gitlab::Diff::Position.new(
+ old_path: path,
+ new_path: path,
+ old_line: nil,
+ new_line: 14,
+ diff_refs: merge_request.diff_refs
+ )
+ end
+
+ render_views
+
+ before(:all) do
+ clean_frontend_fixtures('merge_request_diffs/')
+ end
+
+ before(:each) do
+ sign_in(admin)
+ end
+
+ it 'merge_request_diffs/inline_changes_tab_with_comments.json' do |example|
+ create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
+ create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
+ render_merge_request(example.description, merge_request)
+ end
+
+ it 'merge_request_diffs/parallel_changes_tab_with_comments.json' do |example|
+ create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
+ create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
+ render_merge_request(example.description, merge_request, view: 'parallel')
+ end
+
+ private
+
+ def render_merge_request(fixture_file_name, merge_request, view: 'inline')
+ get :show,
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.to_param,
+ format: :json,
+ view: view
+
+ expect(response).to be_success
+ store_frontend_fixture(response, fixture_file_name)
+ end
+end
diff --git a/spec/javascripts/fixtures/oauth_remember_me.html.haml b/spec/javascripts/fixtures/oauth_remember_me.html.haml
new file mode 100644
index 00000000000..7886e995e57
--- /dev/null
+++ b/spec/javascripts/fixtures/oauth_remember_me.html.haml
@@ -0,0 +1,5 @@
+#oauth-container
+ %input#remember_me{ type: "checkbox" }
+
+ %a.oauth-login.twitter{ href: "http://example.com/" }
+ %a.oauth-login.github{ href: "http://example.com/" }
diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb
new file mode 100644
index 00000000000..3200577b326
--- /dev/null
+++ b/spec/javascripts/fixtures/prometheus_service.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe Projects::ServicesController, '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:admin) { create(:admin) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project_empty_repo, namespace: namespace, path: 'services-project') }
+ let!(:service) { create(:prometheus_service, project: project) }
+
+ render_views
+
+ before(:all) do
+ clean_frontend_fixtures('services/prometheus')
+ end
+
+ before(:each) do
+ sign_in(admin)
+ end
+
+ it 'services/prometheus/prometheus_service.html.raw' do |example|
+ get :edit,
+ namespace_id: namespace,
+ project_id: project,
+ id: service.to_param
+
+ expect(response).to be_success
+ store_frontend_fixture(response, example.description)
+ end
+end
diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb
index c9c0b891237..e3d7986f2cf 100644
--- a/spec/javascripts/fixtures/u2f.rb
+++ b/spec/javascripts/fixtures/u2f.rb
@@ -10,10 +10,12 @@ context 'U2F' do
end
describe SessionsController, '(JavaScript fixtures)', type: :controller do
+ include DeviseHelpers
+
render_views
before do
- @request.env['devise.mapping'] = Devise.mappings[:user]
+ set_devise_mapping(context: @request)
end
it 'u2f/authenticate.html.raw' do |example|
diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js
index 2a77f7259da..aaffb56fa94 100644
--- a/spec/javascripts/groups/groups_spec.js
+++ b/spec/javascripts/groups/groups_spec.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import eventHub from '~/groups/event_hub';
import groupFolderComponent from '~/groups/components/group_folder.vue';
import groupItemComponent from '~/groups/components/group_item.vue';
import groupsComponent from '~/groups/components/groups.vue';
@@ -46,6 +47,12 @@ describe('Groups Component', () => {
expect(component.$el.querySelector('#group-1120')).toBeDefined();
});
+ it('should respect the order of groups', () => {
+ const wrap = component.$el.querySelector('.groups-list-tree-container > .group-list-tree');
+ expect(wrap.querySelector('.group-row:nth-child(1)').id).toBe('group-12');
+ expect(wrap.querySelector('.group-row:nth-child(2)').id).toBe('group-1119');
+ });
+
it('should render group and its subgroup', () => {
const lists = component.$el.querySelectorAll('.group-list-tree');
@@ -54,11 +61,26 @@ describe('Groups Component', () => {
expect(lists[0].querySelector('#group-1119').classList.contains('is-open')).toBe(true);
expect(lists[0].querySelector('#group-1119').classList.contains('has-subgroups')).toBe(true);
- expect(lists[2].querySelector('#group-1120').textContent).toContain(groups[1119].subGroups[1120].name);
+ expect(lists[2].querySelector('#group-1120').textContent).toContain(groups.id1119.subGroups.id1120.name);
});
it('should remove prefix of parent group', () => {
expect(component.$el.querySelector('#group-12 #group-1128 .title').textContent).toContain('level2 / level3 / level4');
});
+
+ it('should remove the group after leaving the group', (done) => {
+ spyOn(window, 'confirm').and.returnValue(true);
+
+ eventHub.$on('leaveGroup', (group, collection) => {
+ store.removeGroup(group, collection);
+ });
+
+ component.$el.querySelector('#group-12 .leave-group').click();
+
+ Vue.nextTick(() => {
+ expect(component.$el.querySelector('#group-12')).toBeNull();
+ done();
+ });
+ });
});
});
diff --git a/spec/javascripts/helpers/vue_resource_helper.js b/spec/javascripts/helpers/vue_resource_helper.js
new file mode 100644
index 00000000000..0d1bf5e2e80
--- /dev/null
+++ b/spec/javascripts/helpers/vue_resource_helper.js
@@ -0,0 +1,11 @@
+// eslint-disable-next-line import/prefer-default-export
+export const headersInterceptor = (request, next) => {
+ next((response) => {
+ const headers = {};
+ response.headers.forEach((value, key) => {
+ headers[key] = value;
+ });
+ // eslint-disable-next-line no-param-reassign
+ response.headers = headers;
+ });
+};
diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js
index 45909d4e70e..3daeb91b1e2 100644
--- a/spec/javascripts/integrations/integration_settings_form_spec.js
+++ b/spec/javascripts/integrations/integration_settings_form_spec.js
@@ -135,10 +135,10 @@ describe('IntegrationSettingsForm', () => {
integrationSettingsForm.testSettings(formData);
- deferred.resolve({ error: true, message: errorMessage });
+ deferred.resolve({ error: true, message: errorMessage, service_response: 'some error' });
const $flashContainer = $('.flash-container');
- expect($flashContainer.find('.flash-text').text()).toEqual(errorMessage);
+ expect($flashContainer.find('.flash-text').text()).toEqual('Test failed. some error');
expect($flashContainer.find('.flash-action')).toBeDefined();
expect($flashContainer.find('.flash-action').text()).toEqual('Save anyway');
});
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index 276e01fc82f..81ce18bf2fb 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -5,29 +5,30 @@ import issuableApp from '~/issue_show/components/app.vue';
import eventHub from '~/issue_show/event_hub';
import issueShowData from '../mock_data';
-const issueShowInterceptor = data => (request, next) => {
- next(request.respondWith(JSON.stringify(data), {
- status: 200,
- headers: {
- 'POLL-INTERVAL': 1,
- },
- }));
-};
-
function formatText(text) {
return text.trim().replace(/\s\s+/g, ' ');
}
describe('Issuable output', () => {
+ let requestData = issueShowData.initialRequest;
+
document.body.innerHTML = '<span id="task_status"></span>';
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(requestData), {
+ status: 200,
+ }));
+ };
+
let vm;
- beforeEach(() => {
+ beforeEach((done) => {
+ spyOn(eventHub, '$emit');
+
const IssuableDescriptionComponent = Vue.extend(issuableApp);
- Vue.http.interceptors.push(issueShowInterceptor(issueShowData.initialRequest));
- spyOn(eventHub, '$emit');
+ requestData = issueShowData.initialRequest;
+ Vue.http.interceptors.push(interceptor);
vm = new IssuableDescriptionComponent({
propsData: {
@@ -48,15 +49,23 @@ describe('Issuable output', () => {
projectPath: '/',
},
}).$mount();
+
+ setTimeout(done);
});
afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+
+ vm.poll.stop();
});
it('should render a title/description/edited and update title/description/edited on update', (done) => {
- setTimeout(() => {
- const editedText = vm.$el.querySelector('.edited-text');
-
+ let editedText;
+ Vue.nextTick()
+ .then(() => {
+ editedText = vm.$el.querySelector('.edited-text');
+ })
+ .then(() => {
expect(document.querySelector('title').innerText).toContain('this is a title (#1)');
expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>this is a title</p>');
expect(vm.$el.querySelector('.wiki').innerHTML).toContain('<p>this is a description!</p>');
@@ -64,22 +73,24 @@ describe('Issuable output', () => {
expect(formatText(editedText.innerText)).toMatch(/Edited[\s\S]+?by Some User/);
expect(editedText.querySelector('.author_link').href).toMatch(/\/some_user$/);
expect(editedText.querySelector('time')).toBeTruthy();
-
- Vue.http.interceptors.push(issueShowInterceptor(issueShowData.secondRequest));
-
- setTimeout(() => {
- expect(document.querySelector('title').innerText).toContain('2 (#1)');
- expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>2</p>');
- expect(vm.$el.querySelector('.wiki').innerHTML).toContain('<p>42</p>');
- expect(vm.$el.querySelector('.js-task-list-field').value).toContain('42');
- expect(vm.$el.querySelector('.edited-text')).toBeTruthy();
- expect(formatText(vm.$el.querySelector('.edited-text').innerText)).toMatch(/Edited[\s\S]+?by Other User/);
- expect(editedText.querySelector('.author_link').href).toMatch(/\/other_user$/);
- expect(editedText.querySelector('time')).toBeTruthy();
-
- done();
- });
- });
+ })
+ .then(() => {
+ requestData = issueShowData.secondRequest;
+ vm.poll.makeRequest();
+ })
+ .then(() => new Promise(resolve => setTimeout(resolve)))
+ .then(() => {
+ expect(document.querySelector('title').innerText).toContain('2 (#1)');
+ expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>2</p>');
+ expect(vm.$el.querySelector('.wiki').innerHTML).toContain('<p>42</p>');
+ expect(vm.$el.querySelector('.js-task-list-field').value).toContain('42');
+ expect(vm.$el.querySelector('.edited-text')).toBeTruthy();
+ expect(formatText(vm.$el.querySelector('.edited-text').innerText)).toMatch(/Edited[\s\S]+?by Other User/);
+ expect(editedText.querySelector('.author_link').href).toMatch(/\/other_user$/);
+ expect(editedText.querySelector('time')).toBeTruthy();
+ })
+ .then(done)
+ .catch(done.fail);
});
it('shows actions if permissions are correct', (done) => {
@@ -301,7 +312,7 @@ describe('Issuable output', () => {
it('stops polling when deleting', (done) => {
spyOn(gl.utils, 'visitUrl');
- spyOn(vm.poll, 'stop');
+ spyOn(vm.poll, 'stop').and.callThrough();
spyOn(vm.service, 'deleteIssuable').and.callFake(() => new Promise((resolve) => {
resolve({
json() {
@@ -344,21 +355,14 @@ describe('Issuable output', () => {
describe('open form', () => {
it('shows locked warning if form is open & data is different', (done) => {
- Vue.http.interceptors.push(issueShowInterceptor(issueShowData.initialRequest));
-
Vue.nextTick()
- .then(() => new Promise((resolve) => {
- setTimeout(resolve);
- }))
.then(() => {
vm.openForm();
- Vue.http.interceptors.push(issueShowInterceptor(issueShowData.secondRequest));
-
- return new Promise((resolve) => {
- setTimeout(resolve);
- });
+ requestData = issueShowData.secondRequest;
+ vm.poll.makeRequest();
})
+ .then(() => new Promise(resolve => setTimeout(resolve)))
.then(() => {
expect(
vm.formState.lockedWarningVisible,
@@ -367,9 +371,8 @@ describe('Issuable output', () => {
expect(
vm.$el.querySelector('.alert'),
).not.toBeNull();
-
- done();
})
+ .then(done)
.catch(done.fail);
});
});
diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js
index f3fdbff01a6..360691a3546 100644
--- a/spec/javascripts/issue_show/components/description_spec.js
+++ b/spec/javascripts/issue_show/components/description_spec.js
@@ -44,32 +44,34 @@ describe('Description component', () => {
});
});
- it('re-inits the TaskList when description changed', (done) => {
- spyOn(gl, 'TaskList');
- vm.descriptionHtml = 'changed';
-
- setTimeout(() => {
- expect(
- gl.TaskList,
- ).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('does not re-init the TaskList when canUpdate is false', (done) => {
- spyOn(gl, 'TaskList');
- vm.canUpdate = false;
- vm.descriptionHtml = 'changed';
-
- setTimeout(() => {
- expect(
- gl.TaskList,
- ).not.toHaveBeenCalled();
-
- done();
- });
- });
+ // TODO: gl.TaskList no longer exists. rewrite these tests once we have a way to rewire ES modules
+
+ // it('re-inits the TaskList when description changed', (done) => {
+ // spyOn(gl, 'TaskList');
+ // vm.descriptionHtml = 'changed';
+ //
+ // setTimeout(() => {
+ // expect(
+ // gl.TaskList,
+ // ).toHaveBeenCalled();
+ //
+ // done();
+ // });
+ // });
+
+ // it('does not re-init the TaskList when canUpdate is false', (done) => {
+ // spyOn(gl, 'TaskList');
+ // vm.canUpdate = false;
+ // vm.descriptionHtml = 'changed';
+ //
+ // setTimeout(() => {
+ // expect(
+ // gl.TaskList,
+ // ).not.toHaveBeenCalled();
+ //
+ // done();
+ // });
+ // });
describe('taskStatus', () => {
it('adds full taskStatus', (done) => {
diff --git a/spec/javascripts/issue_show/components/fields/description_spec.js b/spec/javascripts/issue_show/components/fields/description_spec.js
index f5b35b1e8b0..df8189d9290 100644
--- a/spec/javascripts/issue_show/components/fields/description_spec.js
+++ b/spec/javascripts/issue_show/components/fields/description_spec.js
@@ -1,6 +1,8 @@
import Vue from 'vue';
+import eventHub from '~/issue_show/event_hub';
import Store from '~/issue_show/stores';
import descriptionField from '~/issue_show/components/fields/description.vue';
+import { keyboardDownEvent } from '../../helpers';
describe('Description field component', () => {
let vm;
@@ -18,6 +20,8 @@ describe('Description field component', () => {
document.body.appendChild(el);
+ spyOn(eventHub, '$emit');
+
vm = new Component({
el,
propsData: {
@@ -53,4 +57,20 @@ describe('Description field component', () => {
document.activeElement,
).toBe(vm.$refs.textarea);
});
+
+ it('triggers update with meta+enter', () => {
+ vm.$el.querySelector('.md-area textarea').dispatchEvent(keyboardDownEvent(13, true));
+
+ expect(
+ eventHub.$emit,
+ ).toHaveBeenCalled();
+ });
+
+ it('triggers update with ctrl+enter', () => {
+ vm.$el.querySelector('.md-area textarea').dispatchEvent(keyboardDownEvent(13, false, true));
+
+ expect(
+ eventHub.$emit,
+ ).toHaveBeenCalled();
+ });
});
diff --git a/spec/javascripts/issue_show/components/fields/title_spec.js b/spec/javascripts/issue_show/components/fields/title_spec.js
index 53ae038a6a2..a03b462689f 100644
--- a/spec/javascripts/issue_show/components/fields/title_spec.js
+++ b/spec/javascripts/issue_show/components/fields/title_spec.js
@@ -1,6 +1,8 @@
import Vue from 'vue';
+import eventHub from '~/issue_show/event_hub';
import Store from '~/issue_show/stores';
import titleField from '~/issue_show/components/fields/title.vue';
+import { keyboardDownEvent } from '../../helpers';
describe('Title field component', () => {
let vm;
@@ -15,6 +17,8 @@ describe('Title field component', () => {
});
store.formState.title = 'test';
+ spyOn(eventHub, '$emit');
+
vm = new Component({
propsData: {
formState: store.formState,
@@ -27,4 +31,20 @@ describe('Title field component', () => {
vm.$el.querySelector('.form-control').value,
).toBe('test');
});
+
+ it('triggers update with meta+enter', () => {
+ vm.$el.querySelector('.form-control').dispatchEvent(keyboardDownEvent(13, true));
+
+ expect(
+ eventHub.$emit,
+ ).toHaveBeenCalled();
+ });
+
+ it('triggers update with ctrl+enter', () => {
+ vm.$el.querySelector('.form-control').dispatchEvent(keyboardDownEvent(13, false, true));
+
+ expect(
+ eventHub.$emit,
+ ).toHaveBeenCalled();
+ });
});
diff --git a/spec/javascripts/issue_show/helpers.js b/spec/javascripts/issue_show/helpers.js
new file mode 100644
index 00000000000..5d2ced98ae4
--- /dev/null
+++ b/spec/javascripts/issue_show/helpers.js
@@ -0,0 +1,10 @@
+// eslint-disable-next-line import/prefer-default-export
+export const keyboardDownEvent = (code, metaKey = false, ctrlKey = false) => {
+ const e = new CustomEvent('keydown');
+
+ e.keyCode = code;
+ e.metaKey = metaKey;
+ e.ctrlKey = ctrlKey;
+
+ return e;
+};
diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js
index df97a100b0d..0c8c4d2cea6 100644
--- a/spec/javascripts/issue_spec.js
+++ b/spec/javascripts/issue_spec.js
@@ -1,10 +1,10 @@
/* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
import Issue from '~/issue';
-
+import CloseReopenReportToggle from '~/close_reopen_report_toggle';
import '~/lib/utils/text_utility';
describe('Issue', function() {
- let $boxClosed, $boxOpen, $btnClose, $btnReopen;
+ let $boxClosed, $boxOpen, $btn;
preloadFixtures('issues/closed-issue.html.raw');
preloadFixtures('issues/issue-with-task-list.html.raw');
@@ -20,9 +20,7 @@ describe('Issue', function() {
function expectIssueState(isIssueOpen) {
expectVisibility($boxClosed, !isIssueOpen);
expectVisibility($boxOpen, isIssueOpen);
-
- expectVisibility($btnClose, isIssueOpen);
- expectVisibility($btnReopen, !isIssueOpen);
+ expect($btn).toHaveText(isIssueOpen ? 'Close issue' : 'Reopen issue');
}
function expectNewBranchButtonState(isPending, canCreate) {
@@ -57,7 +55,7 @@ describe('Issue', function() {
}
}
- function findElements() {
+ function findElements(isIssueInitiallyOpen) {
$boxClosed = $('div.status-box-closed');
expect($boxClosed).toExist();
expect($boxClosed).toHaveText('Closed');
@@ -66,13 +64,9 @@ describe('Issue', function() {
expect($boxOpen).toExist();
expect($boxOpen).toHaveText('Open');
- $btnClose = $('.btn-close.btn-grouped');
- expect($btnClose).toExist();
- expect($btnClose).toHaveText('Close issue');
-
- $btnReopen = $('.btn-reopen.btn-grouped');
- expect($btnReopen).toExist();
- expect($btnReopen).toHaveText('Reopen issue');
+ $btn = $('.js-issuable-close-button');
+ expect($btn).toExist();
+ expect($btn).toHaveText(isIssueInitiallyOpen ? 'Close issue' : 'Reopen issue');
}
describe('task lists', function() {
@@ -99,7 +93,6 @@ describe('Issue', function() {
function ajaxSpy(req) {
if (req.url === this.$triggeredButton.attr('href')) {
expect(req.type).toBe('PUT');
- expect(this.$triggeredButton).toHaveProp('disabled', true);
expectNewBranchButtonState(true, false);
return this.issueStateDeferred;
} else if (req.url === Issue.createMrDropdownWrap.dataset.canCreatePath) {
@@ -119,10 +112,11 @@ describe('Issue', function() {
loadFixtures('issues/closed-issue.html.raw');
}
- findElements();
+ findElements(isIssueInitiallyOpen);
this.issue = new Issue();
expectIssueState(isIssueInitiallyOpen);
- this.$triggeredButton = isIssueInitiallyOpen ? $btnClose : $btnReopen;
+
+ this.$triggeredButton = $btn;
this.$projectIssuesCounter = $('.issue_counter');
this.$projectIssuesCounter.text('1,001');
@@ -143,7 +137,7 @@ describe('Issue', function() {
});
expectIssueState(!isIssueInitiallyOpen);
- expect(this.$triggeredButton).toHaveProp('disabled', false);
+ expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expect(this.$projectIssuesCounter.text()).toBe(isIssueInitiallyOpen ? '1,000' : '1,002');
expectNewBranchButtonState(false, !isIssueInitiallyOpen);
});
@@ -158,7 +152,7 @@ describe('Issue', function() {
});
expectIssueState(isIssueInitiallyOpen);
- expect(this.$triggeredButton).toHaveProp('disabled', false);
+ expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expectErrorMessage();
expect(this.$projectIssuesCounter.text()).toBe('1,001');
expectNewBranchButtonState(false, isIssueInitiallyOpen);
@@ -172,7 +166,7 @@ describe('Issue', function() {
});
expectIssueState(isIssueInitiallyOpen);
- expect(this.$triggeredButton).toHaveProp('disabled', true);
+ expect(this.$triggeredButton.get(0).getAttribute('disabled')).toBeNull();
expectErrorMessage();
expect(this.$projectIssuesCounter.text()).toBe('1,001');
expectNewBranchButtonState(false, isIssueInitiallyOpen);
@@ -195,4 +189,37 @@ describe('Issue', function() {
});
});
});
+
+ describe('units', () => {
+ describe('class constructor', () => {
+ it('calls .initCloseReopenReport', () => {
+ spyOn(Issue.prototype, 'initCloseReopenReport');
+
+ new Issue(); // eslint-disable-line no-new
+
+ expect(Issue.prototype.initCloseReopenReport).toHaveBeenCalled();
+ });
+ });
+
+ describe('initCloseReopenReport', () => {
+ it('calls .initDroplab', () => {
+ const container = jasmine.createSpyObj('container', ['querySelector']);
+ const dropdownTrigger = {};
+ const dropdownList = {};
+ const button = {};
+
+ spyOn(document, 'querySelector').and.returnValue(container);
+ spyOn(CloseReopenReportToggle.prototype, 'initDroplab');
+ container.querySelector.and.returnValues(dropdownTrigger, dropdownList, button);
+
+ Issue.prototype.initCloseReopenReport();
+
+ expect(document.querySelector).toHaveBeenCalledWith('.js-issuable-close-dropdown');
+ expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-toggle');
+ expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-menu');
+ expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-button');
+ expect(CloseReopenReportToggle.prototype.initDroplab).toHaveBeenCalled();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js
new file mode 100644
index 00000000000..1d81e4e2d1a
--- /dev/null
+++ b/spec/javascripts/lazy_loader_spec.js
@@ -0,0 +1,57 @@
+import LazyLoader from '~/lazy_loader';
+
+let lazyLoader = null;
+
+describe('LazyLoader', function () {
+ preloadFixtures('issues/issue_with_comment.html.raw');
+
+ beforeEach(function () {
+ loadFixtures('issues/issue_with_comment.html.raw');
+ lazyLoader = new LazyLoader({
+ observerNode: 'body',
+ });
+ // Doing everything that happens normally in onload
+ lazyLoader.loadCheck();
+ });
+ describe('behavior', function () {
+ it('should copy value from data-src to src for img 1', function (done) {
+ const img = document.querySelectorAll('img[data-src]')[0];
+ const originalDataSrc = img.getAttribute('data-src');
+ img.scrollIntoView();
+
+ setTimeout(() => {
+ expect(img.getAttribute('src')).toBe(originalDataSrc);
+ expect(document.getElementsByClassName('js-lazy-loaded').length).toBeGreaterThan(0);
+ done();
+ }, 100);
+ });
+
+ it('should lazy load dynamically added data-src images', function (done) {
+ const newImg = document.createElement('img');
+ const testPath = '/img/testimg.png';
+ newImg.className = 'lazy';
+ newImg.setAttribute('data-src', testPath);
+ document.body.appendChild(newImg);
+ newImg.scrollIntoView();
+
+ setTimeout(() => {
+ expect(newImg.getAttribute('src')).toBe(testPath);
+ expect(document.getElementsByClassName('js-lazy-loaded').length).toBeGreaterThan(0);
+ done();
+ }, 100);
+ });
+
+ it('should not alter normal images', function (done) {
+ const newImg = document.createElement('img');
+ const testPath = '/img/testimg.png';
+ newImg.setAttribute('src', testPath);
+ document.body.appendChild(newImg);
+ newImg.scrollIntoView();
+
+ setTimeout(() => {
+ expect(newImg).not.toHaveClass('js-lazy-loaded');
+ done();
+ }, 100);
+ });
+ });
+});
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 52cf217c25f..55037bbbf73 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -143,6 +143,7 @@ import '~/lib/utils/common_utils';
it('should return valid parameter', () => {
const value = gl.utils.getParameterByName('scope');
+ expect(gl.utils.getParameterByName('p')).toEqual('2');
expect(value).toBe('all');
});
diff --git a/spec/javascripts/lib/utils/dom_utils_spec.js b/spec/javascripts/lib/utils/dom_utils_spec.js
new file mode 100644
index 00000000000..867bf5912d1
--- /dev/null
+++ b/spec/javascripts/lib/utils/dom_utils_spec.js
@@ -0,0 +1,35 @@
+import { addClassIfElementExists } from '~/lib/utils/dom_utils';
+
+describe('DOM Utils', () => {
+ describe('addClassIfElementExists', () => {
+ const className = 'biology';
+ const fixture = `
+ <div class="parent">
+ <div class="child"></div>
+ </div>
+ `;
+
+ let parentElement;
+
+ beforeEach(() => {
+ setFixtures(fixture);
+ parentElement = document.querySelector('.parent');
+ });
+
+ it('adds class if element exists', () => {
+ const childElement = parentElement.querySelector('.child');
+ expect(childElement).not.toBe(null);
+
+ addClassIfElementExists(childElement, className);
+
+ expect(childElement.classList).toContain(className);
+ });
+
+ it('does not throw if element does not exist', () => {
+ const childElement = parentElement.querySelector('.other-child');
+ expect(childElement).toBe(null);
+
+ addClassIfElementExists(childElement, className);
+ });
+ });
+});
diff --git a/spec/javascripts/lib/utils/poll_spec.js b/spec/javascripts/lib/utils/poll_spec.js
index 22f30191ab9..2aa7011ca51 100644
--- a/spec/javascripts/lib/utils/poll_spec.js
+++ b/spec/javascripts/lib/utils/poll_spec.js
@@ -25,23 +25,28 @@ function mockServiceCall(service, response, shouldFail = false) {
describe('Poll', () => {
const service = jasmine.createSpyObj('service', ['fetch']);
- const callbacks = jasmine.createSpyObj('callbacks', ['success', 'error']);
+ const callbacks = jasmine.createSpyObj('callbacks', ['success', 'error', 'notification']);
+
+ function setup() {
+ return new Poll({
+ resource: service,
+ method: 'fetch',
+ successCallback: callbacks.success,
+ errorCallback: callbacks.error,
+ notificationCallback: callbacks.notification,
+ }).makeRequest();
+ }
afterEach(() => {
callbacks.success.calls.reset();
callbacks.error.calls.reset();
+ callbacks.notification.calls.reset();
service.fetch.calls.reset();
});
it('calls the success callback when no header for interval is provided', (done) => {
mockServiceCall(service, { status: 200 });
-
- new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- }).makeRequest();
+ setup();
waitForAllCallsToFinish(service, 1, () => {
expect(callbacks.success).toHaveBeenCalled();
@@ -51,15 +56,9 @@ describe('Poll', () => {
});
});
- it('calls the error callback whe the http request returns an error', (done) => {
+ it('calls the error callback when the http request returns an error', (done) => {
mockServiceCall(service, { status: 500 }, true);
-
- new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- }).makeRequest();
+ setup();
waitForAllCallsToFinish(service, 1, () => {
expect(callbacks.success).not.toHaveBeenCalled();
@@ -69,15 +68,22 @@ describe('Poll', () => {
});
});
+ it('skips the error callback when request is aborted', (done) => {
+ mockServiceCall(service, { status: 0 }, true);
+ setup();
+
+ waitForAllCallsToFinish(service, 1, () => {
+ expect(callbacks.success).not.toHaveBeenCalled();
+ expect(callbacks.error).not.toHaveBeenCalled();
+ expect(callbacks.notification).toHaveBeenCalled();
+
+ done();
+ });
+ });
+
it('should call the success callback when the interval header is -1', (done) => {
mockServiceCall(service, { status: 200, headers: { 'poll-interval': -1 } });
-
- new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- }).makeRequest().then(() => {
+ setup().then(() => {
expect(callbacks.success).toHaveBeenCalled();
expect(callbacks.error).not.toHaveBeenCalled();
diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js
index b6d0ce02c4f..395dc560671 100644
--- a/spec/javascripts/merge_request_notes_spec.js
+++ b/spec/javascripts/merge_request_notes_spec.js
@@ -15,7 +15,7 @@ describe('Merge request notes', () => {
gl.utils = gl.utils || {};
const discussionTabFixture = 'merge_requests/diff_comment.html.raw';
- const changesTabJsonFixture = 'merge_requests/changes_tab_with_comments.json';
+ const changesTabJsonFixture = 'merge_request_diffs/inline_changes_tab_with_comments.json';
preloadFixtures(discussionTabFixture, changesTabJsonFixture);
describe('Discussion tab with diff comments', () => {
diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js
index f444bcaf847..6ff42e2378d 100644
--- a/spec/javascripts/merge_request_spec.js
+++ b/spec/javascripts/merge_request_spec.js
@@ -2,10 +2,12 @@
/* global MergeRequest */
import '~/merge_request';
+import CloseReopenReportToggle from '~/close_reopen_report_toggle';
+import IssuablesHelper from '~/helpers/issuables_helper';
(function() {
describe('MergeRequest', function() {
- return describe('task lists', function() {
+ describe('task lists', function() {
preloadFixtures('merge_requests/merge_request_with_task_list.html.raw');
beforeEach(function() {
loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
@@ -27,5 +29,34 @@ import '~/merge_request';
return $('.js-task-list-field').trigger('tasklist:changed');
});
});
+
+ describe('class constructor', () => {
+ it('calls .initCloseReopenReport', () => {
+ spyOn(IssuablesHelper, 'initCloseReopenReport');
+
+ new MergeRequest(); // eslint-disable-line no-new
+
+ expect(IssuablesHelper.initCloseReopenReport).toHaveBeenCalled();
+ });
+
+ it('calls .initDroplab', () => {
+ const container = jasmine.createSpyObj('container', ['querySelector']);
+ const dropdownTrigger = {};
+ const dropdownList = {};
+ const button = {};
+
+ spyOn(CloseReopenReportToggle.prototype, 'initDroplab');
+ spyOn(document, 'querySelector').and.returnValue(container);
+ container.querySelector.and.returnValues(dropdownTrigger, dropdownList, button);
+
+ new MergeRequest(); // eslint-disable-line no-new
+
+ expect(document.querySelector).toHaveBeenCalledWith('.js-issuable-close-dropdown');
+ expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-toggle');
+ expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-menu');
+ expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-button');
+ expect(CloseReopenReportToggle.prototype.initDroplab).toHaveBeenCalled();
+ });
+ });
});
}).call(window);
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index 9916d2c1e21..dc40244c20e 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -6,7 +6,6 @@ import '~/commit/pipelines/pipelines_bundle';
import '~/breakpoints';
import '~/lib/utils/common_utils';
import '~/diff';
-import '~/single_file_diff';
import '~/files_comment_button';
import '~/notes';
import 'vendor/jquery.scrollTo';
@@ -22,7 +21,15 @@ import 'vendor/jquery.scrollTo';
};
$.extend(stubLocation, defaults, stubs || {});
};
- preloadFixtures('merge_requests/merge_request_with_task_list.html.raw', 'merge_requests/diff_comment.html.raw');
+
+ const inlineChangesTabJsonFixture = 'merge_request_diffs/inline_changes_tab_with_comments.json';
+ const parallelChangesTabJsonFixture = 'merge_request_diffs/parallel_changes_tab_with_comments.json';
+ preloadFixtures(
+ 'merge_requests/merge_request_with_task_list.html.raw',
+ 'merge_requests/diff_comment.html.raw',
+ inlineChangesTabJsonFixture,
+ parallelChangesTabJsonFixture
+ );
beforeEach(function () {
this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation });
@@ -44,14 +51,10 @@ import 'vendor/jquery.scrollTo';
loadFixtures('merge_requests/merge_request_with_task_list.html.raw');
this.subject = this.class.activateTab;
});
- it('shows the first tab when action is show', function () {
+ it('shows the notes tab when action is show', function () {
this.subject('show');
expect($('#notes')).toHaveClass('active');
});
- it('shows the notes tab when action is notes', function () {
- this.subject('notes');
- expect($('#notes')).toHaveClass('active');
- });
it('shows the commits tab when action is commits', function () {
this.subject('commits');
expect($('#commits')).toHaveClass('active');
@@ -153,7 +156,7 @@ import 'vendor/jquery.scrollTo';
setLocation({
pathname: '/foo/bar/merge_requests/1/commits'
});
- expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1');
+ expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
expect(this.subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs');
});
@@ -162,7 +165,7 @@ import 'vendor/jquery.scrollTo';
pathname: '/foo/bar/merge_requests/1/diffs'
});
- expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1');
+ expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
});
@@ -170,7 +173,7 @@ import 'vendor/jquery.scrollTo';
setLocation({
pathname: '/foo/bar/merge_requests/1/diffs.html'
});
- expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1');
+ expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
});
@@ -271,6 +274,19 @@ import 'vendor/jquery.scrollTo';
});
describe('loadDiff', function () {
+ beforeEach(() => {
+ loadFixtures('merge_requests/diff_comment.html.raw');
+ spyOn(window.gl.utils, 'getPagePath').and.returnValue('merge_requests');
+ window.gl.ImageFile = () => {};
+ window.notes = new Notes('', []);
+ spyOn(window.notes, 'toggleDiffNote').and.callThrough();
+ });
+
+ afterEach(() => {
+ delete window.gl.ImageFile;
+ delete window.notes;
+ });
+
it('requires an absolute pathname', function () {
spyOn($, 'ajax').and.callFake(function (options) {
expect(options.url).toEqual('/foo/bar/merge_requests/1/diffs.json');
@@ -279,43 +295,112 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
});
- describe('with note fragment hash', () => {
+ describe('with inline diff', () => {
+ let noteId;
+ let noteLineNumId;
+
beforeEach(() => {
- loadFixtures('merge_requests/diff_comment.html.raw');
- spyOn(window.gl.utils, 'getPagePath').and.returnValue('merge_requests');
- window.notes = new Notes('', []);
- spyOn(window.notes, 'toggleDiffNote').and.callThrough();
- });
+ const diffsResponse = getJSONFixture(inlineChangesTabJsonFixture);
+
+ const $html = $(diffsResponse.html);
+ noteId = $html.find('.note').attr('id');
+ noteLineNumId = $html
+ .find('.note')
+ .closest('.notes_holder')
+ .prev('.line_holder')
+ .find('a[data-linenumber]')
+ .attr('href')
+ .replace('#', '');
- afterEach(() => {
- delete window.notes;
+ spyOn($, 'ajax').and.callFake(function (options) {
+ options.success(diffsResponse);
+ });
});
- it('should expand and scroll to linked fragment hash #note_xxx', function () {
- const noteId = 'note_1';
- spyOn(window.gl.utils, 'getLocationHash').and.returnValue(noteId);
- spyOn($, 'ajax').and.callFake(function (options) {
- options.success({ html: `<div id="${noteId}">foo</div>` });
+ describe('with note fragment hash', () => {
+ it('should expand and scroll to linked fragment hash #note_xxx', function () {
+ spyOn(window.gl.utils, 'getLocationHash').and.returnValue(noteId);
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
+
+ expect(noteId.length).toBeGreaterThan(0);
+ expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
+ target: jasmine.any(Object),
+ lineType: 'old',
+ forceShow: true,
+ });
+ });
+
+ it('should gracefully ignore non-existant fragment hash', function () {
+ spyOn(window.gl.utils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
+
+ expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
});
+ });
- this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
+ describe('with line number fragment hash', () => {
+ it('should gracefully ignore line number fragment hash', function () {
+ spyOn(window.gl.utils, 'getLocationHash').and.returnValue(noteLineNumId);
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
- target: jasmine.any(Object),
- lineType: 'old',
- forceShow: true,
+ expect(noteLineNumId.length).toBeGreaterThan(0);
+ expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
});
});
+ });
+
+ describe('with parallel diff', () => {
+ let noteId;
+ let noteLineNumId;
+
+ beforeEach(() => {
+ const diffsResponse = getJSONFixture(parallelChangesTabJsonFixture);
+
+ const $html = $(diffsResponse.html);
+ noteId = $html.find('.note').attr('id');
+ noteLineNumId = $html
+ .find('.note')
+ .closest('.notes_holder')
+ .prev('.line_holder')
+ .find('a[data-linenumber]')
+ .attr('href')
+ .replace('#', '');
- it('should gracefully ignore non-existant fragment hash', function () {
- spyOn(window.gl.utils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
spyOn($, 'ajax').and.callFake(function (options) {
- options.success({ html: '' });
+ options.success(diffsResponse);
+ });
+ });
+
+ describe('with note fragment hash', () => {
+ it('should expand and scroll to linked fragment hash #note_xxx', function () {
+ spyOn(window.gl.utils, 'getLocationHash').and.returnValue(noteId);
+
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
+
+ expect(noteId.length).toBeGreaterThan(0);
+ expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
+ target: jasmine.any(Object),
+ lineType: 'new',
+ forceShow: true,
+ });
});
- this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
+ it('should gracefully ignore non-existant fragment hash', function () {
+ spyOn(window.gl.utils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('with line number fragment hash', () => {
+ it('should gracefully ignore line number fragment hash', function () {
+ spyOn(window.gl.utils, 'getLocationHash').and.returnValue(noteLineNumId);
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
+
+ expect(noteLineNumId.length).toBeGreaterThan(0);
+ expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ });
});
});
});
diff --git a/spec/javascripts/monitoring/deployments_spec.js b/spec/javascripts/monitoring/deployments_spec.js
deleted file mode 100644
index 19bc11d0f24..00000000000
--- a/spec/javascripts/monitoring/deployments_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import d3 from 'd3';
-import PrometheusGraph from '~/monitoring/prometheus_graph';
-import Deployments from '~/monitoring/deployments';
-import { prometheusMockData } from './prometheus_mock_data';
-
-describe('Metrics deployments', () => {
- const fixtureName = 'environments/metrics/metrics.html.raw';
- let deployment;
- let prometheusGraph;
-
- const graphElement = () => document.querySelector('.prometheus-graph');
-
- preloadFixtures(fixtureName);
-
- beforeEach((done) => {
- // Setup the view
- loadFixtures(fixtureName);
-
- d3.selectAll('.prometheus-graph')
- .append('g')
- .attr('class', 'graph-container');
-
- prometheusGraph = new PrometheusGraph();
- deployment = new Deployments(1000, 500);
-
- spyOn(prometheusGraph, 'init');
- spyOn($, 'ajax').and.callFake(() => {
- const d = $.Deferred();
- d.resolve({
- deployments: [{
- id: 1,
- created_at: deployment.chartData[10].time,
- sha: 'testing',
- tag: false,
- ref: {
- name: 'testing',
- },
- }, {
- id: 2,
- created_at: deployment.chartData[15].time,
- sha: '',
- tag: true,
- ref: {
- name: 'tag',
- },
- }],
- });
-
- setTimeout(done);
-
- return d.promise();
- });
-
- prometheusGraph.configureGraph();
- prometheusGraph.transformData(prometheusMockData.metrics);
-
- deployment.init(prometheusGraph.graphSpecificProperties.memory_values.data);
- });
-
- it('creates line on graph for deploment', () => {
- expect(
- graphElement().querySelectorAll('.deployment-line').length,
- ).toBe(2);
- });
-
- it('creates hidden deploy boxes', () => {
- expect(
- graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box').length,
- ).toBe(2);
- });
-
- it('hides the info boxes by default', () => {
- expect(
- graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box.hidden').length,
- ).toBe(2);
- });
-
- it('shows sha short code when tag is false', () => {
- expect(
- graphElement().querySelector('.deploy-info-1-cpu_values .js-deploy-info-box').textContent.trim(),
- ).toContain('testin');
- });
-
- it('shows ref name when tag is true', () => {
- expect(
- graphElement().querySelector('.deploy-info-2-cpu_values .js-deploy-info-box').textContent.trim(),
- ).toContain('tag');
- });
-
- it('shows info box when moving mouse over line', () => {
- deployment.mouseOverDeployInfo(deployment.data[0].xPos, 'cpu_values');
-
- expect(
- graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box.hidden').length,
- ).toBe(1);
-
- expect(
- graphElement().querySelector('.deploy-info-1-cpu_values .js-deploy-info-box.hidden'),
- ).toBeNull();
- });
-
- it('hides previously visible info box when moving mouse away', () => {
- deployment.mouseOverDeployInfo(500, 'cpu_values');
-
- expect(
- graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box.hidden').length,
- ).toBe(2);
-
- expect(
- graphElement().querySelector('.deploy-info-1-cpu_values .js-deploy-info-box.hidden'),
- ).not.toBeNull();
- });
-
- describe('refText', () => {
- it('returns shortened SHA', () => {
- expect(
- Deployments.refText({
- tag: false,
- sha: '123456789',
- }),
- ).toBe('123456');
- });
-
- it('returns tag name', () => {
- expect(
- Deployments.refText({
- tag: true,
- ref: 'v1.0',
- }),
- ).toBe('v1.0');
- });
- });
-});
diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js
new file mode 100644
index 00000000000..b69f4eddffc
--- /dev/null
+++ b/spec/javascripts/monitoring/mock_data.js
@@ -0,0 +1,4230 @@
+/* eslint-disable quote-props, indent, comma-dangle */
+
+const metricsGroupsAPIResponse = {
+ 'success': true,
+ 'data': [
+ {
+ 'group': 'Kubernetes',
+ 'priority': 1,
+ 'metrics': [
+ {
+ 'title': 'Memory usage',
+ 'weight': 1,
+ 'queries': [
+ {
+ 'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20',
+ 'y_label': 'Memory',
+ 'unit': 'MiB',
+ 'result': [
+ {
+ 'metric': {},
+ 'values': [
+ [
+ 1495700554.925,
+ '8.0390625'
+ ],
+ [
+ 1495700614.925,
+ '8.0390625'
+ ],
+ [
+ 1495700674.925,
+ '8.0390625'
+ ],
+ [
+ 1495700734.925,
+ '8.0390625'
+ ],
+ [
+ 1495700794.925,
+ '8.0390625'
+ ],
+ [
+ 1495700854.925,
+ '8.0390625'
+ ],
+ [
+ 1495700914.925,
+ '8.0390625'
+ ],
+ [
+ 1495700974.925,
+ '8.0390625'
+ ],
+ [
+ 1495701034.925,
+ '8.0390625'
+ ],
+ [
+ 1495701094.925,
+ '8.0390625'
+ ],
+ [
+ 1495701154.925,
+ '8.0390625'
+ ],
+ [
+ 1495701214.925,
+ '8.0390625'
+ ],
+ [
+ 1495701274.925,
+ '8.0390625'
+ ],
+ [
+ 1495701334.925,
+ '8.0390625'
+ ],
+ [
+ 1495701394.925,
+ '8.0390625'
+ ],
+ [
+ 1495701454.925,
+ '8.0390625'
+ ],
+ [
+ 1495701514.925,
+ '8.0390625'
+ ],
+ [
+ 1495701574.925,
+ '8.0390625'
+ ],
+ [
+ 1495701634.925,
+ '8.0390625'
+ ],
+ [
+ 1495701694.925,
+ '8.0390625'
+ ],
+ [
+ 1495701754.925,
+ '8.0390625'
+ ],
+ [
+ 1495701814.925,
+ '8.0390625'
+ ],
+ [
+ 1495701874.925,
+ '8.0390625'
+ ],
+ [
+ 1495701934.925,
+ '8.0390625'
+ ],
+ [
+ 1495701994.925,
+ '8.0390625'
+ ],
+ [
+ 1495702054.925,
+ '8.0390625'
+ ],
+ [
+ 1495702114.925,
+ '8.0390625'
+ ],
+ [
+ 1495702174.925,
+ '8.0390625'
+ ],
+ [
+ 1495702234.925,
+ '8.0390625'
+ ],
+ [
+ 1495702294.925,
+ '8.0390625'
+ ],
+ [
+ 1495702354.925,
+ '8.0390625'
+ ],
+ [
+ 1495702414.925,
+ '8.0390625'
+ ],
+ [
+ 1495702474.925,
+ '8.0390625'
+ ],
+ [
+ 1495702534.925,
+ '8.0390625'
+ ],
+ [
+ 1495702594.925,
+ '8.0390625'
+ ],
+ [
+ 1495702654.925,
+ '8.0390625'
+ ],
+ [
+ 1495702714.925,
+ '8.0390625'
+ ],
+ [
+ 1495702774.925,
+ '8.0390625'
+ ],
+ [
+ 1495702834.925,
+ '8.0390625'
+ ],
+ [
+ 1495702894.925,
+ '8.0390625'
+ ],
+ [
+ 1495702954.925,
+ '8.0390625'
+ ],
+ [
+ 1495703014.925,
+ '8.0390625'
+ ],
+ [
+ 1495703074.925,
+ '8.0390625'
+ ],
+ [
+ 1495703134.925,
+ '8.0390625'
+ ],
+ [
+ 1495703194.925,
+ '8.0390625'
+ ],
+ [
+ 1495703254.925,
+ '8.03515625'
+ ],
+ [
+ 1495703314.925,
+ '8.03515625'
+ ],
+ [
+ 1495703374.925,
+ '8.03515625'
+ ],
+ [
+ 1495703434.925,
+ '8.03515625'
+ ],
+ [
+ 1495703494.925,
+ '8.03515625'
+ ],
+ [
+ 1495703554.925,
+ '8.03515625'
+ ],
+ [
+ 1495703614.925,
+ '8.03515625'
+ ],
+ [
+ 1495703674.925,
+ '8.03515625'
+ ],
+ [
+ 1495703734.925,
+ '8.03515625'
+ ],
+ [
+ 1495703794.925,
+ '8.03515625'
+ ],
+ [
+ 1495703854.925,
+ '8.03515625'
+ ],
+ [
+ 1495703914.925,
+ '8.03515625'
+ ],
+ [
+ 1495703974.925,
+ '8.03515625'
+ ],
+ [
+ 1495704034.925,
+ '8.03515625'
+ ],
+ [
+ 1495704094.925,
+ '8.03515625'
+ ],
+ [
+ 1495704154.925,
+ '8.03515625'
+ ],
+ [
+ 1495704214.925,
+ '7.9296875'
+ ],
+ [
+ 1495704274.925,
+ '7.9296875'
+ ],
+ [
+ 1495704334.925,
+ '7.9296875'
+ ],
+ [
+ 1495704394.925,
+ '7.9296875'
+ ],
+ [
+ 1495704454.925,
+ '7.9296875'
+ ],
+ [
+ 1495704514.925,
+ '7.9296875'
+ ],
+ [
+ 1495704574.925,
+ '7.9296875'
+ ],
+ [
+ 1495704634.925,
+ '7.9296875'
+ ],
+ [
+ 1495704694.925,
+ '7.9296875'
+ ],
+ [
+ 1495704754.925,
+ '7.9296875'
+ ],
+ [
+ 1495704814.925,
+ '7.9296875'
+ ],
+ [
+ 1495704874.925,
+ '7.9296875'
+ ],
+ [
+ 1495704934.925,
+ '7.9296875'
+ ],
+ [
+ 1495704994.925,
+ '7.9296875'
+ ],
+ [
+ 1495705054.925,
+ '7.9296875'
+ ],
+ [
+ 1495705114.925,
+ '7.9296875'
+ ],
+ [
+ 1495705174.925,
+ '7.9296875'
+ ],
+ [
+ 1495705234.925,
+ '7.9296875'
+ ],
+ [
+ 1495705294.925,
+ '7.9296875'
+ ],
+ [
+ 1495705354.925,
+ '7.9296875'
+ ],
+ [
+ 1495705414.925,
+ '7.9296875'
+ ],
+ [
+ 1495705474.925,
+ '7.9296875'
+ ],
+ [
+ 1495705534.925,
+ '7.9296875'
+ ],
+ [
+ 1495705594.925,
+ '7.9296875'
+ ],
+ [
+ 1495705654.925,
+ '7.9296875'
+ ],
+ [
+ 1495705714.925,
+ '7.9296875'
+ ],
+ [
+ 1495705774.925,
+ '7.9296875'
+ ],
+ [
+ 1495705834.925,
+ '7.9296875'
+ ],
+ [
+ 1495705894.925,
+ '7.9296875'
+ ],
+ [
+ 1495705954.925,
+ '7.9296875'
+ ],
+ [
+ 1495706014.925,
+ '7.9296875'
+ ],
+ [
+ 1495706074.925,
+ '7.9296875'
+ ],
+ [
+ 1495706134.925,
+ '7.9296875'
+ ],
+ [
+ 1495706194.925,
+ '7.9296875'
+ ],
+ [
+ 1495706254.925,
+ '7.9296875'
+ ],
+ [
+ 1495706314.925,
+ '7.9296875'
+ ],
+ [
+ 1495706374.925,
+ '7.9296875'
+ ],
+ [
+ 1495706434.925,
+ '7.9296875'
+ ],
+ [
+ 1495706494.925,
+ '7.9296875'
+ ],
+ [
+ 1495706554.925,
+ '7.9296875'
+ ],
+ [
+ 1495706614.925,
+ '7.9296875'
+ ],
+ [
+ 1495706674.925,
+ '7.9296875'
+ ],
+ [
+ 1495706734.925,
+ '7.9296875'
+ ],
+ [
+ 1495706794.925,
+ '7.9296875'
+ ],
+ [
+ 1495706854.925,
+ '7.9296875'
+ ],
+ [
+ 1495706914.925,
+ '7.9296875'
+ ],
+ [
+ 1495706974.925,
+ '7.9296875'
+ ],
+ [
+ 1495707034.925,
+ '7.9296875'
+ ],
+ [
+ 1495707094.925,
+ '7.9296875'
+ ],
+ [
+ 1495707154.925,
+ '7.9296875'
+ ],
+ [
+ 1495707214.925,
+ '7.9296875'
+ ],
+ [
+ 1495707274.925,
+ '7.9296875'
+ ],
+ [
+ 1495707334.925,
+ '7.9296875'
+ ],
+ [
+ 1495707394.925,
+ '7.9296875'
+ ],
+ [
+ 1495707454.925,
+ '7.9296875'
+ ],
+ [
+ 1495707514.925,
+ '7.9296875'
+ ],
+ [
+ 1495707574.925,
+ '7.9296875'
+ ],
+ [
+ 1495707634.925,
+ '7.9296875'
+ ],
+ [
+ 1495707694.925,
+ '7.9296875'
+ ],
+ [
+ 1495707754.925,
+ '7.9296875'
+ ],
+ [
+ 1495707814.925,
+ '7.9296875'
+ ],
+ [
+ 1495707874.925,
+ '7.9296875'
+ ],
+ [
+ 1495707934.925,
+ '7.9296875'
+ ],
+ [
+ 1495707994.925,
+ '7.9296875'
+ ],
+ [
+ 1495708054.925,
+ '7.9296875'
+ ],
+ [
+ 1495708114.925,
+ '7.9296875'
+ ],
+ [
+ 1495708174.925,
+ '7.9296875'
+ ],
+ [
+ 1495708234.925,
+ '7.9296875'
+ ],
+ [
+ 1495708294.925,
+ '7.9296875'
+ ],
+ [
+ 1495708354.925,
+ '7.9296875'
+ ],
+ [
+ 1495708414.925,
+ '7.9296875'
+ ],
+ [
+ 1495708474.925,
+ '7.9296875'
+ ],
+ [
+ 1495708534.925,
+ '7.9296875'
+ ],
+ [
+ 1495708594.925,
+ '7.9296875'
+ ],
+ [
+ 1495708654.925,
+ '7.9296875'
+ ],
+ [
+ 1495708714.925,
+ '7.9296875'
+ ],
+ [
+ 1495708774.925,
+ '7.9296875'
+ ],
+ [
+ 1495708834.925,
+ '7.9296875'
+ ],
+ [
+ 1495708894.925,
+ '7.9296875'
+ ],
+ [
+ 1495708954.925,
+ '7.8984375'
+ ],
+ [
+ 1495709014.925,
+ '7.8984375'
+ ],
+ [
+ 1495709074.925,
+ '7.8984375'
+ ],
+ [
+ 1495709134.925,
+ '7.8984375'
+ ],
+ [
+ 1495709194.925,
+ '7.8984375'
+ ],
+ [
+ 1495709254.925,
+ '7.89453125'
+ ],
+ [
+ 1495709314.925,
+ '7.89453125'
+ ],
+ [
+ 1495709374.925,
+ '7.89453125'
+ ],
+ [
+ 1495709434.925,
+ '7.89453125'
+ ],
+ [
+ 1495709494.925,
+ '7.89453125'
+ ],
+ [
+ 1495709554.925,
+ '7.89453125'
+ ],
+ [
+ 1495709614.925,
+ '7.89453125'
+ ],
+ [
+ 1495709674.925,
+ '7.89453125'
+ ],
+ [
+ 1495709734.925,
+ '7.89453125'
+ ],
+ [
+ 1495709794.925,
+ '7.89453125'
+ ],
+ [
+ 1495709854.925,
+ '7.89453125'
+ ],
+ [
+ 1495709914.925,
+ '7.89453125'
+ ],
+ [
+ 1495709974.925,
+ '7.89453125'
+ ],
+ [
+ 1495710034.925,
+ '7.89453125'
+ ],
+ [
+ 1495710094.925,
+ '7.89453125'
+ ],
+ [
+ 1495710154.925,
+ '7.89453125'
+ ],
+ [
+ 1495710214.925,
+ '7.89453125'
+ ],
+ [
+ 1495710274.925,
+ '7.89453125'
+ ],
+ [
+ 1495710334.925,
+ '7.89453125'
+ ],
+ [
+ 1495710394.925,
+ '7.89453125'
+ ],
+ [
+ 1495710454.925,
+ '7.89453125'
+ ],
+ [
+ 1495710514.925,
+ '7.89453125'
+ ],
+ [
+ 1495710574.925,
+ '7.89453125'
+ ],
+ [
+ 1495710634.925,
+ '7.89453125'
+ ],
+ [
+ 1495710694.925,
+ '7.89453125'
+ ],
+ [
+ 1495710754.925,
+ '7.89453125'
+ ],
+ [
+ 1495710814.925,
+ '7.89453125'
+ ],
+ [
+ 1495710874.925,
+ '7.89453125'
+ ],
+ [
+ 1495710934.925,
+ '7.89453125'
+ ],
+ [
+ 1495710994.925,
+ '7.89453125'
+ ],
+ [
+ 1495711054.925,
+ '7.89453125'
+ ],
+ [
+ 1495711114.925,
+ '7.89453125'
+ ],
+ [
+ 1495711174.925,
+ '7.8515625'
+ ],
+ [
+ 1495711234.925,
+ '7.8515625'
+ ],
+ [
+ 1495711294.925,
+ '7.8515625'
+ ],
+ [
+ 1495711354.925,
+ '7.8515625'
+ ],
+ [
+ 1495711414.925,
+ '7.8515625'
+ ],
+ [
+ 1495711474.925,
+ '7.8515625'
+ ],
+ [
+ 1495711534.925,
+ '7.8515625'
+ ],
+ [
+ 1495711594.925,
+ '7.8515625'
+ ],
+ [
+ 1495711654.925,
+ '7.8515625'
+ ],
+ [
+ 1495711714.925,
+ '7.8515625'
+ ],
+ [
+ 1495711774.925,
+ '7.8515625'
+ ],
+ [
+ 1495711834.925,
+ '7.8515625'
+ ],
+ [
+ 1495711894.925,
+ '7.8515625'
+ ],
+ [
+ 1495711954.925,
+ '7.8515625'
+ ],
+ [
+ 1495712014.925,
+ '7.8515625'
+ ],
+ [
+ 1495712074.925,
+ '7.8515625'
+ ],
+ [
+ 1495712134.925,
+ '7.8515625'
+ ],
+ [
+ 1495712194.925,
+ '7.8515625'
+ ],
+ [
+ 1495712254.925,
+ '7.8515625'
+ ],
+ [
+ 1495712314.925,
+ '7.8515625'
+ ],
+ [
+ 1495712374.925,
+ '7.8515625'
+ ],
+ [
+ 1495712434.925,
+ '7.83203125'
+ ],
+ [
+ 1495712494.925,
+ '7.83203125'
+ ],
+ [
+ 1495712554.925,
+ '7.83203125'
+ ],
+ [
+ 1495712614.925,
+ '7.83203125'
+ ],
+ [
+ 1495712674.925,
+ '7.83203125'
+ ],
+ [
+ 1495712734.925,
+ '7.83203125'
+ ],
+ [
+ 1495712794.925,
+ '7.83203125'
+ ],
+ [
+ 1495712854.925,
+ '7.83203125'
+ ],
+ [
+ 1495712914.925,
+ '7.83203125'
+ ],
+ [
+ 1495712974.925,
+ '7.83203125'
+ ],
+ [
+ 1495713034.925,
+ '7.83203125'
+ ],
+ [
+ 1495713094.925,
+ '7.83203125'
+ ],
+ [
+ 1495713154.925,
+ '7.83203125'
+ ],
+ [
+ 1495713214.925,
+ '7.83203125'
+ ],
+ [
+ 1495713274.925,
+ '7.83203125'
+ ],
+ [
+ 1495713334.925,
+ '7.83203125'
+ ],
+ [
+ 1495713394.925,
+ '7.8125'
+ ],
+ [
+ 1495713454.925,
+ '7.8125'
+ ],
+ [
+ 1495713514.925,
+ '7.8125'
+ ],
+ [
+ 1495713574.925,
+ '7.8125'
+ ],
+ [
+ 1495713634.925,
+ '7.8125'
+ ],
+ [
+ 1495713694.925,
+ '7.8125'
+ ],
+ [
+ 1495713754.925,
+ '7.8125'
+ ],
+ [
+ 1495713814.925,
+ '7.8125'
+ ],
+ [
+ 1495713874.925,
+ '7.8125'
+ ],
+ [
+ 1495713934.925,
+ '7.8125'
+ ],
+ [
+ 1495713994.925,
+ '7.8125'
+ ],
+ [
+ 1495714054.925,
+ '7.8125'
+ ],
+ [
+ 1495714114.925,
+ '7.8125'
+ ],
+ [
+ 1495714174.925,
+ '7.8125'
+ ],
+ [
+ 1495714234.925,
+ '7.8125'
+ ],
+ [
+ 1495714294.925,
+ '7.8125'
+ ],
+ [
+ 1495714354.925,
+ '7.80859375'
+ ],
+ [
+ 1495714414.925,
+ '7.80859375'
+ ],
+ [
+ 1495714474.925,
+ '7.80859375'
+ ],
+ [
+ 1495714534.925,
+ '7.80859375'
+ ],
+ [
+ 1495714594.925,
+ '7.80859375'
+ ],
+ [
+ 1495714654.925,
+ '7.80859375'
+ ],
+ [
+ 1495714714.925,
+ '7.80859375'
+ ],
+ [
+ 1495714774.925,
+ '7.80859375'
+ ],
+ [
+ 1495714834.925,
+ '7.80859375'
+ ],
+ [
+ 1495714894.925,
+ '7.80859375'
+ ],
+ [
+ 1495714954.925,
+ '7.80859375'
+ ],
+ [
+ 1495715014.925,
+ '7.80859375'
+ ],
+ [
+ 1495715074.925,
+ '7.80859375'
+ ],
+ [
+ 1495715134.925,
+ '7.80859375'
+ ],
+ [
+ 1495715194.925,
+ '7.80859375'
+ ],
+ [
+ 1495715254.925,
+ '7.80859375'
+ ],
+ [
+ 1495715314.925,
+ '7.80859375'
+ ],
+ [
+ 1495715374.925,
+ '7.80859375'
+ ],
+ [
+ 1495715434.925,
+ '7.80859375'
+ ],
+ [
+ 1495715494.925,
+ '7.80859375'
+ ],
+ [
+ 1495715554.925,
+ '7.80859375'
+ ],
+ [
+ 1495715614.925,
+ '7.80859375'
+ ],
+ [
+ 1495715674.925,
+ '7.80859375'
+ ],
+ [
+ 1495715734.925,
+ '7.80859375'
+ ],
+ [
+ 1495715794.925,
+ '7.80859375'
+ ],
+ [
+ 1495715854.925,
+ '7.80859375'
+ ],
+ [
+ 1495715914.925,
+ '7.80078125'
+ ],
+ [
+ 1495715974.925,
+ '7.80078125'
+ ],
+ [
+ 1495716034.925,
+ '7.80078125'
+ ],
+ [
+ 1495716094.925,
+ '7.80078125'
+ ],
+ [
+ 1495716154.925,
+ '7.80078125'
+ ],
+ [
+ 1495716214.925,
+ '7.796875'
+ ],
+ [
+ 1495716274.925,
+ '7.796875'
+ ],
+ [
+ 1495716334.925,
+ '7.796875'
+ ],
+ [
+ 1495716394.925,
+ '7.796875'
+ ],
+ [
+ 1495716454.925,
+ '7.796875'
+ ],
+ [
+ 1495716514.925,
+ '7.796875'
+ ],
+ [
+ 1495716574.925,
+ '7.796875'
+ ],
+ [
+ 1495716634.925,
+ '7.796875'
+ ],
+ [
+ 1495716694.925,
+ '7.796875'
+ ],
+ [
+ 1495716754.925,
+ '7.796875'
+ ],
+ [
+ 1495716814.925,
+ '7.796875'
+ ],
+ [
+ 1495716874.925,
+ '7.79296875'
+ ],
+ [
+ 1495716934.925,
+ '7.79296875'
+ ],
+ [
+ 1495716994.925,
+ '7.79296875'
+ ],
+ [
+ 1495717054.925,
+ '7.79296875'
+ ],
+ [
+ 1495717114.925,
+ '7.79296875'
+ ],
+ [
+ 1495717174.925,
+ '7.7890625'
+ ],
+ [
+ 1495717234.925,
+ '7.7890625'
+ ],
+ [
+ 1495717294.925,
+ '7.7890625'
+ ],
+ [
+ 1495717354.925,
+ '7.7890625'
+ ],
+ [
+ 1495717414.925,
+ '7.7890625'
+ ],
+ [
+ 1495717474.925,
+ '7.7890625'
+ ],
+ [
+ 1495717534.925,
+ '7.7890625'
+ ],
+ [
+ 1495717594.925,
+ '7.7890625'
+ ],
+ [
+ 1495717654.925,
+ '7.7890625'
+ ],
+ [
+ 1495717714.925,
+ '7.7890625'
+ ],
+ [
+ 1495717774.925,
+ '7.7890625'
+ ],
+ [
+ 1495717834.925,
+ '7.77734375'
+ ],
+ [
+ 1495717894.925,
+ '7.77734375'
+ ],
+ [
+ 1495717954.925,
+ '7.77734375'
+ ],
+ [
+ 1495718014.925,
+ '7.77734375'
+ ],
+ [
+ 1495718074.925,
+ '7.77734375'
+ ],
+ [
+ 1495718134.925,
+ '7.7421875'
+ ],
+ [
+ 1495718194.925,
+ '7.7421875'
+ ],
+ [
+ 1495718254.925,
+ '7.7421875'
+ ],
+ [
+ 1495718314.925,
+ '7.7421875'
+ ]
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ 'title': 'CPU usage',
+ 'weight': 1,
+ 'queries': [
+ {
+ 'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
+ 'result': [
+ {
+ 'metric': {},
+ 'values': [
+ [
+ 1495700554.925,
+ '0.0010794445585559514'
+ ],
+ [
+ 1495700614.925,
+ '0.003927214935433527'
+ ],
+ [
+ 1495700674.925,
+ '0.0053045219047619975'
+ ],
+ [
+ 1495700734.925,
+ '0.0048892095238097155'
+ ],
+ [
+ 1495700794.925,
+ '0.005827140952381137'
+ ],
+ [
+ 1495700854.925,
+ '0.00569846906219937'
+ ],
+ [
+ 1495700914.925,
+ '0.004972616802849382'
+ ],
+ [
+ 1495700974.925,
+ '0.005117509523809902'
+ ],
+ [
+ 1495701034.925,
+ '0.00512389061919564'
+ ],
+ [
+ 1495701094.925,
+ '0.005199100501890691'
+ ],
+ [
+ 1495701154.925,
+ '0.005415746394885837'
+ ],
+ [
+ 1495701214.925,
+ '0.005607682788146286'
+ ],
+ [
+ 1495701274.925,
+ '0.005641300000000118'
+ ],
+ [
+ 1495701334.925,
+ '0.0071166279368766495'
+ ],
+ [
+ 1495701394.925,
+ '0.0063242138095234044'
+ ],
+ [
+ 1495701454.925,
+ '0.005793314698235304'
+ ],
+ [
+ 1495701514.925,
+ '0.00703934942237556'
+ ],
+ [
+ 1495701574.925,
+ '0.006357007076123191'
+ ],
+ [
+ 1495701634.925,
+ '0.003753167300126738'
+ ],
+ [
+ 1495701694.925,
+ '0.005018469678430698'
+ ],
+ [
+ 1495701754.925,
+ '0.0045217153371887'
+ ],
+ [
+ 1495701814.925,
+ '0.006140104285714119'
+ ],
+ [
+ 1495701874.925,
+ '0.004818684285714102'
+ ],
+ [
+ 1495701934.925,
+ '0.005079509718955242'
+ ],
+ [
+ 1495701994.925,
+ '0.005059981142498263'
+ ],
+ [
+ 1495702054.925,
+ '0.005269098389538773'
+ ],
+ [
+ 1495702114.925,
+ '0.005269954285714175'
+ ],
+ [
+ 1495702174.925,
+ '0.014199241435795856'
+ ],
+ [
+ 1495702234.925,
+ '0.01511936843111017'
+ ],
+ [
+ 1495702294.925,
+ '0.0060933692920682875'
+ ],
+ [
+ 1495702354.925,
+ '0.004945682380952493'
+ ],
+ [
+ 1495702414.925,
+ '0.005641266666666565'
+ ],
+ [
+ 1495702474.925,
+ '0.005223752857142996'
+ ],
+ [
+ 1495702534.925,
+ '0.005743098505699831'
+ ],
+ [
+ 1495702594.925,
+ '0.00538493380952391'
+ ],
+ [
+ 1495702654.925,
+ '0.005507793883751339'
+ ],
+ [
+ 1495702714.925,
+ '0.005666705714285466'
+ ],
+ [
+ 1495702774.925,
+ '0.006231530000000112'
+ ],
+ [
+ 1495702834.925,
+ '0.006570768635394899'
+ ],
+ [
+ 1495702894.925,
+ '0.005551146666666895'
+ ],
+ [
+ 1495702954.925,
+ '0.005602604737098058'
+ ],
+ [
+ 1495703014.925,
+ '0.00613993580402159'
+ ],
+ [
+ 1495703074.925,
+ '0.004770258764368832'
+ ],
+ [
+ 1495703134.925,
+ '0.005512376671364914'
+ ],
+ [
+ 1495703194.925,
+ '0.005254436666666674'
+ ],
+ [
+ 1495703254.925,
+ '0.0050109839141320505'
+ ],
+ [
+ 1495703314.925,
+ '0.0049478019256960016'
+ ],
+ [
+ 1495703374.925,
+ '0.0037666860965123463'
+ ],
+ [
+ 1495703434.925,
+ '0.004813526061656314'
+ ],
+ [
+ 1495703494.925,
+ '0.005047748095238278'
+ ],
+ [
+ 1495703554.925,
+ '0.00386494081008772'
+ ],
+ [
+ 1495703614.925,
+ '0.004304037408111405'
+ ],
+ [
+ 1495703674.925,
+ '0.004999466661587168'
+ ],
+ [
+ 1495703734.925,
+ '0.004689140476190834'
+ ],
+ [
+ 1495703794.925,
+ '0.004746126153582475'
+ ],
+ [
+ 1495703854.925,
+ '0.004482706382572302'
+ ],
+ [
+ 1495703914.925,
+ '0.004032808931864524'
+ ],
+ [
+ 1495703974.925,
+ '0.005728319047618988'
+ ],
+ [
+ 1495704034.925,
+ '0.004436139179627006'
+ ],
+ [
+ 1495704094.925,
+ '0.004553455714285617'
+ ],
+ [
+ 1495704154.925,
+ '0.003455244285714341'
+ ],
+ [
+ 1495704214.925,
+ '0.004742244761904621'
+ ],
+ [
+ 1495704274.925,
+ '0.005366978571428422'
+ ],
+ [
+ 1495704334.925,
+ '0.004257954837665058'
+ ],
+ [
+ 1495704394.925,
+ '0.005431603259831257'
+ ],
+ [
+ 1495704454.925,
+ '0.0052009214498621986'
+ ],
+ [
+ 1495704514.925,
+ '0.004317201904761618'
+ ],
+ [
+ 1495704574.925,
+ '0.004307384285714157'
+ ],
+ [
+ 1495704634.925,
+ '0.004789801146644822'
+ ],
+ [
+ 1495704694.925,
+ '0.0051429795906706485'
+ ],
+ [
+ 1495704754.925,
+ '0.005322495714285479'
+ ],
+ [
+ 1495704814.925,
+ '0.004512809333244233'
+ ],
+ [
+ 1495704874.925,
+ '0.004953843582568726'
+ ],
+ [
+ 1495704934.925,
+ '0.005812690120858119'
+ ],
+ [
+ 1495704994.925,
+ '0.004997024285714838'
+ ],
+ [
+ 1495705054.925,
+ '0.005246216154439592'
+ ],
+ [
+ 1495705114.925,
+ '0.0063494966618726795'
+ ],
+ [
+ 1495705174.925,
+ '0.005306004342898225'
+ ],
+ [
+ 1495705234.925,
+ '0.005081412857142978'
+ ],
+ [
+ 1495705294.925,
+ '0.00511409523809522'
+ ],
+ [
+ 1495705354.925,
+ '0.0047861001481192'
+ ],
+ [
+ 1495705414.925,
+ '0.005107688228042962'
+ ],
+ [
+ 1495705474.925,
+ '0.005271929582294012'
+ ],
+ [
+ 1495705534.925,
+ '0.004453254502681249'
+ ],
+ [
+ 1495705594.925,
+ '0.005799134293959226'
+ ],
+ [
+ 1495705654.925,
+ '0.005340865929502478'
+ ],
+ [
+ 1495705714.925,
+ '0.004911654761904942'
+ ],
+ [
+ 1495705774.925,
+ '0.005888234873953261'
+ ],
+ [
+ 1495705834.925,
+ '0.005565283333332954'
+ ],
+ [
+ 1495705894.925,
+ '0.005522869047618869'
+ ],
+ [
+ 1495705954.925,
+ '0.005177549737621646'
+ ],
+ [
+ 1495706014.925,
+ '0.0053145810232096465'
+ ],
+ [
+ 1495706074.925,
+ '0.004751095238095275'
+ ],
+ [
+ 1495706134.925,
+ '0.006242077142856976'
+ ],
+ [
+ 1495706194.925,
+ '0.00621034406957871'
+ ],
+ [
+ 1495706254.925,
+ '0.006887592738978596'
+ ],
+ [
+ 1495706314.925,
+ '0.006328128779726213'
+ ],
+ [
+ 1495706374.925,
+ '0.007488363809523927'
+ ],
+ [
+ 1495706434.925,
+ '0.006193758571428157'
+ ],
+ [
+ 1495706494.925,
+ '0.0068798371839706935'
+ ],
+ [
+ 1495706554.925,
+ '0.005757034340423128'
+ ],
+ [
+ 1495706614.925,
+ '0.004571388497294698'
+ ],
+ [
+ 1495706674.925,
+ '0.00620283044923395'
+ ],
+ [
+ 1495706734.925,
+ '0.005607562380952455'
+ ],
+ [
+ 1495706794.925,
+ '0.005506969933620308'
+ ],
+ [
+ 1495706854.925,
+ '0.005621118095238131'
+ ],
+ [
+ 1495706914.925,
+ '0.004876606098698849'
+ ],
+ [
+ 1495706974.925,
+ '0.0047871205988517206'
+ ],
+ [
+ 1495707034.925,
+ '0.00526405939458784'
+ ],
+ [
+ 1495707094.925,
+ '0.005716323800605852'
+ ],
+ [
+ 1495707154.925,
+ '0.005301459523809575'
+ ],
+ [
+ 1495707214.925,
+ '0.0051613042857144905'
+ ],
+ [
+ 1495707274.925,
+ '0.005384792857142714'
+ ],
+ [
+ 1495707334.925,
+ '0.005259719047619222'
+ ],
+ [
+ 1495707394.925,
+ '0.00584101142857182'
+ ],
+ [
+ 1495707454.925,
+ '0.0060066121920326326'
+ ],
+ [
+ 1495707514.925,
+ '0.006359978571428453'
+ ],
+ [
+ 1495707574.925,
+ '0.006315876322151109'
+ ],
+ [
+ 1495707634.925,
+ '0.005590012517198831'
+ ],
+ [
+ 1495707694.925,
+ '0.005517419877137072'
+ ],
+ [
+ 1495707754.925,
+ '0.006089813430348506'
+ ],
+ [
+ 1495707814.925,
+ '0.00466754476190479'
+ ],
+ [
+ 1495707874.925,
+ '0.006059954380517721'
+ ],
+ [
+ 1495707934.925,
+ '0.005085657142856972'
+ ],
+ [
+ 1495707994.925,
+ '0.005897665238095296'
+ ],
+ [
+ 1495708054.925,
+ '0.0062282023199555885'
+ ],
+ [
+ 1495708114.925,
+ '0.00526214553236979'
+ ],
+ [
+ 1495708174.925,
+ '0.0044803300000000644'
+ ],
+ [
+ 1495708234.925,
+ '0.005421443333333592'
+ ],
+ [
+ 1495708294.925,
+ '0.005694326244512144'
+ ],
+ [
+ 1495708354.925,
+ '0.005527721904761457'
+ ],
+ [
+ 1495708414.925,
+ '0.005988819523809819'
+ ],
+ [
+ 1495708474.925,
+ '0.005484704285714448'
+ ],
+ [
+ 1495708534.925,
+ '0.005041123649230085'
+ ],
+ [
+ 1495708594.925,
+ '0.005717767639612059'
+ ],
+ [
+ 1495708654.925,
+ '0.005412954417342863'
+ ],
+ [
+ 1495708714.925,
+ '0.005833343333333254'
+ ],
+ [
+ 1495708774.925,
+ '0.005448135238094969'
+ ],
+ [
+ 1495708834.925,
+ '0.005117341428571432'
+ ],
+ [
+ 1495708894.925,
+ '0.005888345825277833'
+ ],
+ [
+ 1495708954.925,
+ '0.005398543809524135'
+ ],
+ [
+ 1495709014.925,
+ '0.005325611428571416'
+ ],
+ [
+ 1495709074.925,
+ '0.005848668571428527'
+ ],
+ [
+ 1495709134.925,
+ '0.005135003105145044'
+ ],
+ [
+ 1495709194.925,
+ '0.0054551400000003'
+ ],
+ [
+ 1495709254.925,
+ '0.005319472937322171'
+ ],
+ [
+ 1495709314.925,
+ '0.00585677857142792'
+ ],
+ [
+ 1495709374.925,
+ '0.0062146261904759215'
+ ],
+ [
+ 1495709434.925,
+ '0.0067105060904182265'
+ ],
+ [
+ 1495709494.925,
+ '0.005829691904762108'
+ ],
+ [
+ 1495709554.925,
+ '0.005719280952381261'
+ ],
+ [
+ 1495709614.925,
+ '0.005682603793416407'
+ ],
+ [
+ 1495709674.925,
+ '0.0055272846277326934'
+ ],
+ [
+ 1495709734.925,
+ '0.0057123680952386735'
+ ],
+ [
+ 1495709794.925,
+ '0.00520597958075818'
+ ],
+ [
+ 1495709854.925,
+ '0.005584358957263837'
+ ],
+ [
+ 1495709914.925,
+ '0.005601104275197466'
+ ],
+ [
+ 1495709974.925,
+ '0.005991657142857066'
+ ],
+ [
+ 1495710034.925,
+ '0.00553722238095218'
+ ],
+ [
+ 1495710094.925,
+ '0.005127883122696293'
+ ],
+ [
+ 1495710154.925,
+ '0.005498111927534584'
+ ],
+ [
+ 1495710214.925,
+ '0.005609934069084202'
+ ],
+ [
+ 1495710274.925,
+ '0.00459206285714307'
+ ],
+ [
+ 1495710334.925,
+ '0.0047910828571428084'
+ ],
+ [
+ 1495710394.925,
+ '0.0056014671288845685'
+ ],
+ [
+ 1495710454.925,
+ '0.005686936791078528'
+ ],
+ [
+ 1495710514.925,
+ '0.00444480476190448'
+ ],
+ [
+ 1495710574.925,
+ '0.005780394696738921'
+ ],
+ [
+ 1495710634.925,
+ '0.0053107227550210365'
+ ],
+ [
+ 1495710694.925,
+ '0.005096031495761817'
+ ],
+ [
+ 1495710754.925,
+ '0.005451377979091524'
+ ],
+ [
+ 1495710814.925,
+ '0.005328136666667083'
+ ],
+ [
+ 1495710874.925,
+ '0.006020612857143043'
+ ],
+ [
+ 1495710934.925,
+ '0.0061063585714285365'
+ ],
+ [
+ 1495710994.925,
+ '0.006018346015752312'
+ ],
+ [
+ 1495711054.925,
+ '0.005069130952381193'
+ ],
+ [
+ 1495711114.925,
+ '0.005458406190476052'
+ ],
+ [
+ 1495711174.925,
+ '0.00577219190476179'
+ ],
+ [
+ 1495711234.925,
+ '0.005760814645658314'
+ ],
+ [
+ 1495711294.925,
+ '0.005371875716579101'
+ ],
+ [
+ 1495711354.925,
+ '0.0064232666666665834'
+ ],
+ [
+ 1495711414.925,
+ '0.009369806836906667'
+ ],
+ [
+ 1495711474.925,
+ '0.008956864761904692'
+ ],
+ [
+ 1495711534.925,
+ '0.005266849368559271'
+ ],
+ [
+ 1495711594.925,
+ '0.005335111364934262'
+ ],
+ [
+ 1495711654.925,
+ '0.006461778319586945'
+ ],
+ [
+ 1495711714.925,
+ '0.004687939890762393'
+ ],
+ [
+ 1495711774.925,
+ '0.004438831245760684'
+ ],
+ [
+ 1495711834.925,
+ '0.005142786666666613'
+ ],
+ [
+ 1495711894.925,
+ '0.007257734212054963'
+ ],
+ [
+ 1495711954.925,
+ '0.005621991904761494'
+ ],
+ [
+ 1495712014.925,
+ '0.007868689999999862'
+ ],
+ [
+ 1495712074.925,
+ '0.00910970215275738'
+ ],
+ [
+ 1495712134.925,
+ '0.006151004285714278'
+ ],
+ [
+ 1495712194.925,
+ '0.005447120924961522'
+ ],
+ [
+ 1495712254.925,
+ '0.005150705153929503'
+ ],
+ [
+ 1495712314.925,
+ '0.006358108714969314'
+ ],
+ [
+ 1495712374.925,
+ '0.0057725354795696475'
+ ],
+ [
+ 1495712434.925,
+ '0.005232139047619015'
+ ],
+ [
+ 1495712494.925,
+ '0.004932809617949037'
+ ],
+ [
+ 1495712554.925,
+ '0.004511607508499662'
+ ],
+ [
+ 1495712614.925,
+ '0.00440487701522666'
+ ],
+ [
+ 1495712674.925,
+ '0.005479113333333174'
+ ],
+ [
+ 1495712734.925,
+ '0.004726317619047547'
+ ],
+ [
+ 1495712794.925,
+ '0.005582041102958029'
+ ],
+ [
+ 1495712854.925,
+ '0.006381481216082099'
+ ],
+ [
+ 1495712914.925,
+ '0.005474260014095208'
+ ],
+ [
+ 1495712974.925,
+ '0.00567597142857188'
+ ],
+ [
+ 1495713034.925,
+ '0.0064741233333332985'
+ ],
+ [
+ 1495713094.925,
+ '0.005467475714285271'
+ ],
+ [
+ 1495713154.925,
+ '0.004868648393824457'
+ ],
+ [
+ 1495713214.925,
+ '0.005254923286444893'
+ ],
+ [
+ 1495713274.925,
+ '0.005599217150312865'
+ ],
+ [
+ 1495713334.925,
+ '0.005105413720618919'
+ ],
+ [
+ 1495713394.925,
+ '0.007246073333333279'
+ ],
+ [
+ 1495713454.925,
+ '0.005990312380952272'
+ ],
+ [
+ 1495713514.925,
+ '0.005594601853351101'
+ ],
+ [
+ 1495713574.925,
+ '0.004739258673727054'
+ ],
+ [
+ 1495713634.925,
+ '0.003932121428571783'
+ ],
+ [
+ 1495713694.925,
+ '0.005018188268459395'
+ ],
+ [
+ 1495713754.925,
+ '0.004538238095237985'
+ ],
+ [
+ 1495713814.925,
+ '0.00561816643265435'
+ ],
+ [
+ 1495713874.925,
+ '0.0063132584495033586'
+ ],
+ [
+ 1495713934.925,
+ '0.00442385238095213'
+ ],
+ [
+ 1495713994.925,
+ '0.004181795887658453'
+ ],
+ [
+ 1495714054.925,
+ '0.004437759047619037'
+ ],
+ [
+ 1495714114.925,
+ '0.006421748157178241'
+ ],
+ [
+ 1495714174.925,
+ '0.006525143809523842'
+ ],
+ [
+ 1495714234.925,
+ '0.004715904935144247'
+ ],
+ [
+ 1495714294.925,
+ '0.005966040152763461'
+ ],
+ [
+ 1495714354.925,
+ '0.005614535466921674'
+ ],
+ [
+ 1495714414.925,
+ '0.004934375119415906'
+ ],
+ [
+ 1495714474.925,
+ '0.0054122933333327385'
+ ],
+ [
+ 1495714534.925,
+ '0.004926540699612279'
+ ],
+ [
+ 1495714594.925,
+ '0.006124649517134237'
+ ],
+ [
+ 1495714654.925,
+ '0.004629427092013995'
+ ],
+ [
+ 1495714714.925,
+ '0.005117951257607005'
+ ],
+ [
+ 1495714774.925,
+ '0.004868774512685422'
+ ],
+ [
+ 1495714834.925,
+ '0.005310093333333399'
+ ],
+ [
+ 1495714894.925,
+ '0.0054907752286127345'
+ ],
+ [
+ 1495714954.925,
+ '0.004597678117351089'
+ ],
+ [
+ 1495715014.925,
+ '0.0059622552380952'
+ ],
+ [
+ 1495715074.925,
+ '0.005352457072655368'
+ ],
+ [
+ 1495715134.925,
+ '0.005491630952381143'
+ ],
+ [
+ 1495715194.925,
+ '0.006391770078379791'
+ ],
+ [
+ 1495715254.925,
+ '0.005933472857142518'
+ ],
+ [
+ 1495715314.925,
+ '0.005301314285714163'
+ ],
+ [
+ 1495715374.925,
+ '0.0058352959724814165'
+ ],
+ [
+ 1495715434.925,
+ '0.006154755147867044'
+ ],
+ [
+ 1495715494.925,
+ '0.009391935637482038'
+ ],
+ [
+ 1495715554.925,
+ '0.007846462857142592'
+ ],
+ [
+ 1495715614.925,
+ '0.00477608215316353'
+ ],
+ [
+ 1495715674.925,
+ '0.006132865238094998'
+ ],
+ [
+ 1495715734.925,
+ '0.006159762457649516'
+ ],
+ [
+ 1495715794.925,
+ '0.005957307073265968'
+ ],
+ [
+ 1495715854.925,
+ '0.006652319091792501'
+ ],
+ [
+ 1495715914.925,
+ '0.005493557402895287'
+ ],
+ [
+ 1495715974.925,
+ '0.0058652434829145166'
+ ],
+ [
+ 1495716034.925,
+ '0.005627400430468021'
+ ],
+ [
+ 1495716094.925,
+ '0.006240656190475609'
+ ],
+ [
+ 1495716154.925,
+ '0.006305997676168624'
+ ],
+ [
+ 1495716214.925,
+ '0.005388057732783248'
+ ],
+ [
+ 1495716274.925,
+ '0.0052814916048421244'
+ ],
+ [
+ 1495716334.925,
+ '0.00699498614272497'
+ ],
+ [
+ 1495716394.925,
+ '0.00627768693035141'
+ ],
+ [
+ 1495716454.925,
+ '0.0042411487048161145'
+ ],
+ [
+ 1495716514.925,
+ '0.005348647473627653'
+ ],
+ [
+ 1495716574.925,
+ '0.0047176657142853975'
+ ],
+ [
+ 1495716634.925,
+ '0.004437898571428686'
+ ],
+ [
+ 1495716694.925,
+ '0.004923527366927261'
+ ],
+ [
+ 1495716754.925,
+ '0.005131935066048421'
+ ],
+ [
+ 1495716814.925,
+ '0.005046949523809611'
+ ],
+ [
+ 1495716874.925,
+ '0.00547184095238092'
+ ],
+ [
+ 1495716934.925,
+ '0.005224140016380444'
+ ],
+ [
+ 1495716994.925,
+ '0.005297991171665292'
+ ],
+ [
+ 1495717054.925,
+ '0.005492965995623498'
+ ],
+ [
+ 1495717114.925,
+ '0.005754660000000403'
+ ],
+ [
+ 1495717174.925,
+ '0.005949557138639285'
+ ],
+ [
+ 1495717234.925,
+ '0.006091816112534666'
+ ],
+ [
+ 1495717294.925,
+ '0.005554210080192063'
+ ],
+ [
+ 1495717354.925,
+ '0.006411504395279871'
+ ],
+ [
+ 1495717414.925,
+ '0.006319643996609606'
+ ],
+ [
+ 1495717474.925,
+ '0.005539174405717675'
+ ],
+ [
+ 1495717534.925,
+ '0.0053157078842772255'
+ ],
+ [
+ 1495717594.925,
+ '0.005247480952381066'
+ ],
+ [
+ 1495717654.925,
+ '0.004820141620396252'
+ ],
+ [
+ 1495717714.925,
+ '0.005906173868322844'
+ ],
+ [
+ 1495717774.925,
+ '0.006173117219570961'
+ ],
+ [
+ 1495717834.925,
+ '0.005963340952380661'
+ ],
+ [
+ 1495717894.925,
+ '0.005698976627681527'
+ ],
+ [
+ 1495717954.925,
+ '0.004751279096346378'
+ ],
+ [
+ 1495718014.925,
+ '0.005733142379359711'
+ ],
+ [
+ 1495718074.925,
+ '0.004831689010348035'
+ ],
+ [
+ 1495718134.925,
+ '0.005188370476191092'
+ ],
+ [
+ 1495718194.925,
+ '0.004793227554547938'
+ ],
+ [
+ 1495718254.925,
+ '0.003997442857142731'
+ ],
+ [
+ 1495718314.925,
+ '0.004386040132951264'
+ ]
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ 'last_update': '2017-05-25T13:18:34.949Z'
+};
+
+export default metricsGroupsAPIResponse;
+
+const responseMockData = {
+ 'GET': {
+ '/root/hello-prometheus/environments/30/additional_metrics.json': metricsGroupsAPIResponse,
+ 'http://test.host/frontend-fixtures/environments-project/environments/1/additional_metrics.json': metricsGroupsAPIResponse, // TODO: MAke sure this works in the monitoring_bundle_spec
+ },
+};
+
+export const deploymentData = [
+ {
+ id: 111,
+ iid: 3,
+ sha: 'f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187',
+ ref: {
+ name: 'master'
+ },
+ created_at: '2017-05-31T21:23:37.881Z',
+ tag: false,
+ 'last?': true
+ },
+ {
+ id: 110,
+ iid: 2,
+ sha: 'f5bcd1d9dac6fa4137e2510b9ccd134ef2e84187',
+ ref: {
+ name: 'master'
+ },
+ created_at: '2017-05-30T20:08:04.629Z',
+ tag: false,
+ 'last?': false
+ },
+ {
+ id: 109,
+ iid: 1,
+ sha: '6511e58faafaa7ad2228990ec57f19d66f7db7c2',
+ ref: {
+ name: 'update2-readme'
+ },
+ created_at: '2017-05-30T17:42:38.409Z',
+ tag: false,
+ 'last?': false
+ }
+];
+
+export const statePaths = {
+ settingsPath: '/root/hello-prometheus/services/prometheus/edit',
+ documentationPath: '/help/administration/monitoring/prometheus/index.md',
+};
+
+export const singleRowMetrics = [
+ {
+ 'title': 'CPU usage',
+ 'weight': 1,
+ 'y_label': 'Memory',
+ 'queries': [
+ {
+ 'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
+ 'label': 'Container CPU',
+ 'result': [
+ {
+ 'metric': {
+
+ },
+ 'values': [
+ {
+ 'time': '2017-06-04T21:22:59.508Z',
+ 'value': '0.06335544298150002'
+ },
+ {
+ 'time': '2017-06-04T21:23:59.508Z',
+ 'value': '0.0420347312480917'
+ },
+ {
+ 'time': '2017-06-04T21:24:59.508Z',
+ 'value': '0.0023175131665412706'
+ },
+ {
+ 'time': '2017-06-04T21:25:59.508Z',
+ 'value': '0.002315870476190476'
+ },
+ {
+ 'time': '2017-06-04T21:26:59.508Z',
+ 'value': '0.0025005961904761894'
+ },
+ {
+ 'time': '2017-06-04T21:27:59.508Z',
+ 'value': '0.0024612605834341264'
+ },
+ {
+ 'time': '2017-06-04T21:28:59.508Z',
+ 'value': '0.002313129398767631'
+ },
+ {
+ 'time': '2017-06-04T21:29:59.508Z',
+ 'value': '0.002411067353663882'
+ },
+ {
+ 'time': '2017-06-04T21:30:59.508Z',
+ 'value': '0.002577309263721303'
+ },
+ {
+ 'time': '2017-06-04T21:31:59.508Z',
+ 'value': '0.00242688307730403'
+ },
+ {
+ 'time': '2017-06-04T21:32:59.508Z',
+ 'value': '0.0024168360301330457'
+ },
+ {
+ 'time': '2017-06-04T21:33:59.508Z',
+ 'value': '0.0020449528090743714'
+ },
+ {
+ 'time': '2017-06-04T21:34:59.508Z',
+ 'value': '0.0019149619047619036'
+ },
+ {
+ 'time': '2017-06-04T21:35:59.508Z',
+ 'value': '0.0024491714364625094'
+ },
+ {
+ 'time': '2017-06-04T21:36:59.508Z',
+ 'value': '0.002728773131172677'
+ },
+ {
+ 'time': '2017-06-04T21:37:59.508Z',
+ 'value': '0.0028439119047618997'
+ },
+ {
+ 'time': '2017-06-04T21:38:59.508Z',
+ 'value': '0.0026307480952380917'
+ },
+ {
+ 'time': '2017-06-04T21:39:59.508Z',
+ 'value': '0.0025024842620546446'
+ },
+ {
+ 'time': '2017-06-04T21:40:59.508Z',
+ 'value': '0.002300662387260825'
+ },
+ {
+ 'time': '2017-06-04T21:41:59.508Z',
+ 'value': '0.002052890924848337'
+ },
+ {
+ 'time': '2017-06-04T21:42:59.508Z',
+ 'value': '0.0023711195238095275'
+ },
+ {
+ 'time': '2017-06-04T21:43:59.508Z',
+ 'value': '0.002513477619047618'
+ },
+ {
+ 'time': '2017-06-04T21:44:59.508Z',
+ 'value': '0.0023489776287844897'
+ },
+ {
+ 'time': '2017-06-04T21:45:59.508Z',
+ 'value': '0.002542572310212481'
+ },
+ {
+ 'time': '2017-06-04T21:46:59.508Z',
+ 'value': '0.0024579470671707952'
+ },
+ {
+ 'time': '2017-06-04T21:47:59.508Z',
+ 'value': '0.0028725150236664403'
+ },
+ {
+ 'time': '2017-06-04T21:48:59.508Z',
+ 'value': '0.0024356089105610525'
+ },
+ {
+ 'time': '2017-06-04T21:49:59.508Z',
+ 'value': '0.002544015828269929'
+ },
+ {
+ 'time': '2017-06-04T21:50:59.508Z',
+ 'value': '0.0029595013380824906'
+ },
+ {
+ 'time': '2017-06-04T21:51:59.508Z',
+ 'value': '0.0023084015085858'
+ },
+ {
+ 'time': '2017-06-04T21:52:59.508Z',
+ 'value': '0.0021070500000000083'
+ },
+ {
+ 'time': '2017-06-04T21:53:59.508Z',
+ 'value': '0.0022950066191106617'
+ },
+ {
+ 'time': '2017-06-04T21:54:59.508Z',
+ 'value': '0.002492719454470995'
+ },
+ {
+ 'time': '2017-06-04T21:55:59.508Z',
+ 'value': '0.00244312761904762'
+ },
+ {
+ 'time': '2017-06-04T21:56:59.508Z',
+ 'value': '0.0023495500000000028'
+ },
+ {
+ 'time': '2017-06-04T21:57:59.508Z',
+ 'value': '0.0020597072353070005'
+ },
+ {
+ 'time': '2017-06-04T21:58:59.508Z',
+ 'value': '0.0021482352044800866'
+ },
+ {
+ 'time': '2017-06-04T21:59:59.508Z',
+ 'value': '0.002333490000000004'
+ },
+ {
+ 'time': '2017-06-04T22:00:59.508Z',
+ 'value': '0.0025899442857142815'
+ },
+ {
+ 'time': '2017-06-04T22:01:59.508Z',
+ 'value': '0.002430299999999999'
+ },
+ {
+ 'time': '2017-06-04T22:02:59.508Z',
+ 'value': '0.0023550328092113476'
+ },
+ {
+ 'time': '2017-06-04T22:03:59.508Z',
+ 'value': '0.0026521871636872793'
+ },
+ {
+ 'time': '2017-06-04T22:04:59.508Z',
+ 'value': '0.0023080671428571398'
+ },
+ {
+ 'time': '2017-06-04T22:05:59.508Z',
+ 'value': '0.0024108401032390896'
+ },
+ {
+ 'time': '2017-06-04T22:06:59.508Z',
+ 'value': '0.002433249366678738'
+ },
+ {
+ 'time': '2017-06-04T22:07:59.508Z',
+ 'value': '0.0023242202306688682'
+ },
+ {
+ 'time': '2017-06-04T22:08:59.508Z',
+ 'value': '0.002388222857142859'
+ },
+ {
+ 'time': '2017-06-04T22:09:59.508Z',
+ 'value': '0.002115974914046794'
+ },
+ {
+ 'time': '2017-06-04T22:10:59.508Z',
+ 'value': '0.0025090043331269917'
+ },
+ {
+ 'time': '2017-06-04T22:11:59.508Z',
+ 'value': '0.002445507057277277'
+ },
+ {
+ 'time': '2017-06-04T22:12:59.508Z',
+ 'value': '0.0026348773751130976'
+ },
+ {
+ 'time': '2017-06-04T22:13:59.508Z',
+ 'value': '0.0025616258583088104'
+ },
+ {
+ 'time': '2017-06-04T22:14:59.508Z',
+ 'value': '0.0021544093415751505'
+ },
+ {
+ 'time': '2017-06-04T22:15:59.508Z',
+ 'value': '0.002649394767668881'
+ },
+ {
+ 'time': '2017-06-04T22:16:59.508Z',
+ 'value': '0.0024023332666685705'
+ },
+ {
+ 'time': '2017-06-04T22:17:59.508Z',
+ 'value': '0.0025444105294235306'
+ },
+ {
+ 'time': '2017-06-04T22:18:59.508Z',
+ 'value': '0.0027298872305772806'
+ },
+ {
+ 'time': '2017-06-04T22:19:59.508Z',
+ 'value': '0.0022880104956379287'
+ },
+ {
+ 'time': '2017-06-04T22:20:59.508Z',
+ 'value': '0.002473246666666661'
+ },
+ {
+ 'time': '2017-06-04T22:21:59.508Z',
+ 'value': '0.002259948381935587'
+ },
+ {
+ 'time': '2017-06-04T22:22:59.508Z',
+ 'value': '0.0025778470886268835'
+ },
+ {
+ 'time': '2017-06-04T22:23:59.508Z',
+ 'value': '0.002246127910852894'
+ },
+ {
+ 'time': '2017-06-04T22:24:59.508Z',
+ 'value': '0.0020697466666666758'
+ },
+ {
+ 'time': '2017-06-04T22:25:59.508Z',
+ 'value': '0.00225859722473547'
+ },
+ {
+ 'time': '2017-06-04T22:26:59.508Z',
+ 'value': '0.0026466728254554814'
+ },
+ {
+ 'time': '2017-06-04T22:27:59.508Z',
+ 'value': '0.002151247619047619'
+ },
+ {
+ 'time': '2017-06-04T22:28:59.508Z',
+ 'value': '0.002324161444543914'
+ },
+ {
+ 'time': '2017-06-04T22:29:59.508Z',
+ 'value': '0.002476474313796452'
+ },
+ {
+ 'time': '2017-06-04T22:30:59.508Z',
+ 'value': '0.0023922184232080517'
+ },
+ {
+ 'time': '2017-06-04T22:31:59.508Z',
+ 'value': '0.0025094934237468933'
+ },
+ {
+ 'time': '2017-06-04T22:32:59.508Z',
+ 'value': '0.0025665311098200883'
+ },
+ {
+ 'time': '2017-06-04T22:33:59.508Z',
+ 'value': '0.0024154900681661374'
+ },
+ {
+ 'time': '2017-06-04T22:34:59.508Z',
+ 'value': '0.0023267450166192037'
+ },
+ {
+ 'time': '2017-06-04T22:35:59.508Z',
+ 'value': '0.002156521904761904'
+ },
+ {
+ 'time': '2017-06-04T22:36:59.508Z',
+ 'value': '0.0025474356898637007'
+ },
+ {
+ 'time': '2017-06-04T22:37:59.508Z',
+ 'value': '0.0025989409624670233'
+ },
+ {
+ 'time': '2017-06-04T22:38:59.508Z',
+ 'value': '0.002348336664762987'
+ },
+ {
+ 'time': '2017-06-04T22:39:59.508Z',
+ 'value': '0.002665888246554726'
+ },
+ {
+ 'time': '2017-06-04T22:40:59.508Z',
+ 'value': '0.002652684787474174'
+ },
+ {
+ 'time': '2017-06-04T22:41:59.508Z',
+ 'value': '0.002472620430865355'
+ },
+ {
+ 'time': '2017-06-04T22:42:59.508Z',
+ 'value': '0.0020616469210110247'
+ },
+ {
+ 'time': '2017-06-04T22:43:59.508Z',
+ 'value': '0.0022434546372311934'
+ },
+ {
+ 'time': '2017-06-04T22:44:59.508Z',
+ 'value': '0.0024469386784827982'
+ },
+ {
+ 'time': '2017-06-04T22:45:59.508Z',
+ 'value': '0.0026192823809523787'
+ },
+ {
+ 'time': '2017-06-04T22:46:59.508Z',
+ 'value': '0.003451999542852798'
+ },
+ {
+ 'time': '2017-06-04T22:47:59.508Z',
+ 'value': '0.0031780314285714288'
+ },
+ {
+ 'time': '2017-06-04T22:48:59.508Z',
+ 'value': '0.0024403352380952415'
+ },
+ {
+ 'time': '2017-06-04T22:49:59.508Z',
+ 'value': '0.001998824761904764'
+ },
+ {
+ 'time': '2017-06-04T22:50:59.508Z',
+ 'value': '0.0023792404761904806'
+ },
+ {
+ 'time': '2017-06-04T22:51:59.508Z',
+ 'value': '0.002725906190476185'
+ },
+ {
+ 'time': '2017-06-04T22:52:59.508Z',
+ 'value': '0.0020989528671155624'
+ },
+ {
+ 'time': '2017-06-04T22:53:59.508Z',
+ 'value': '0.00228808226745016'
+ },
+ {
+ 'time': '2017-06-04T22:54:59.508Z',
+ 'value': '0.0019860807413192147'
+ },
+ {
+ 'time': '2017-06-04T22:55:59.508Z',
+ 'value': '0.0022698085714285897'
+ },
+ {
+ 'time': '2017-06-04T22:56:59.508Z',
+ 'value': '0.0022839098467604415'
+ },
+ {
+ 'time': '2017-06-04T22:57:59.508Z',
+ 'value': '0.002531114761904749'
+ },
+ {
+ 'time': '2017-06-04T22:58:59.508Z',
+ 'value': '0.0028941072550999016'
+ },
+ {
+ 'time': '2017-06-04T22:59:59.508Z',
+ 'value': '0.002547169523809506'
+ },
+ {
+ 'time': '2017-06-04T23:00:59.508Z',
+ 'value': '0.0024062999999999958'
+ },
+ {
+ 'time': '2017-06-04T23:01:59.508Z',
+ 'value': '0.0026939518471604386'
+ },
+ {
+ 'time': '2017-06-04T23:02:59.508Z',
+ 'value': '0.002362901428571429'
+ },
+ {
+ 'time': '2017-06-04T23:03:59.508Z',
+ 'value': '0.002663927142857154'
+ },
+ {
+ 'time': '2017-06-04T23:04:59.508Z',
+ 'value': '0.0026173314285714354'
+ },
+ {
+ 'time': '2017-06-04T23:05:59.508Z',
+ 'value': '0.002326527366406044'
+ },
+ {
+ 'time': '2017-06-04T23:06:59.508Z',
+ 'value': '0.002035313809523809'
+ },
+ {
+ 'time': '2017-06-04T23:07:59.508Z',
+ 'value': '0.002421447414786533'
+ },
+ {
+ 'time': '2017-06-04T23:08:59.508Z',
+ 'value': '0.002898313809523804'
+ },
+ {
+ 'time': '2017-06-04T23:09:59.508Z',
+ 'value': '0.002544891856112907'
+ },
+ {
+ 'time': '2017-06-04T23:10:59.508Z',
+ 'value': '0.002290625356938882'
+ },
+ {
+ 'time': '2017-06-04T23:11:59.508Z',
+ 'value': '0.002483028095238096'
+ },
+ {
+ 'time': '2017-06-04T23:12:59.508Z',
+ 'value': '0.0023396832350784237'
+ },
+ {
+ 'time': '2017-06-04T23:13:59.508Z',
+ 'value': '0.002085529248176153'
+ },
+ {
+ 'time': '2017-06-04T23:14:59.508Z',
+ 'value': '0.0022417815068428012'
+ },
+ {
+ 'time': '2017-06-04T23:15:59.508Z',
+ 'value': '0.002660293333333341'
+ },
+ {
+ 'time': '2017-06-04T23:16:59.508Z',
+ 'value': '0.0029845149093818226'
+ },
+ {
+ 'time': '2017-06-04T23:17:59.508Z',
+ 'value': '0.0027716655079475464'
+ },
+ {
+ 'time': '2017-06-04T23:18:59.508Z',
+ 'value': '0.0025217708908741128'
+ },
+ {
+ 'time': '2017-06-04T23:19:59.508Z',
+ 'value': '0.0025811235131094055'
+ },
+ {
+ 'time': '2017-06-04T23:20:59.508Z',
+ 'value': '0.002209904761904762'
+ },
+ {
+ 'time': '2017-06-04T23:21:59.508Z',
+ 'value': '0.0025053322926383344'
+ },
+ {
+ 'time': '2017-06-04T23:22:59.508Z',
+ 'value': '0.002350917636526411'
+ },
+ {
+ 'time': '2017-06-04T23:23:59.508Z',
+ 'value': '0.0018477500000000078'
+ },
+ {
+ 'time': '2017-06-04T23:24:59.508Z',
+ 'value': '0.002427629523809527'
+ },
+ {
+ 'time': '2017-06-04T23:25:59.508Z',
+ 'value': '0.0019305498147601655'
+ },
+ {
+ 'time': '2017-06-04T23:26:59.508Z',
+ 'value': '0.002097250000000006'
+ },
+ {
+ 'time': '2017-06-04T23:27:59.508Z',
+ 'value': '0.002675020952780041'
+ },
+ {
+ 'time': '2017-06-04T23:28:59.508Z',
+ 'value': '0.0023142214285714374'
+ },
+ {
+ 'time': '2017-06-04T23:29:59.508Z',
+ 'value': '0.0023644723809523737'
+ },
+ {
+ 'time': '2017-06-04T23:30:59.508Z',
+ 'value': '0.002108696190476198'
+ },
+ {
+ 'time': '2017-06-04T23:31:59.508Z',
+ 'value': '0.0019918289697997194'
+ },
+ {
+ 'time': '2017-06-04T23:32:59.508Z',
+ 'value': '0.001583584285714283'
+ },
+ {
+ 'time': '2017-06-04T23:33:59.508Z',
+ 'value': '0.002073770226383112'
+ },
+ {
+ 'time': '2017-06-04T23:34:59.508Z',
+ 'value': '0.0025877664234966818'
+ },
+ {
+ 'time': '2017-06-04T23:35:59.508Z',
+ 'value': '0.0021138238095238147'
+ },
+ {
+ 'time': '2017-06-04T23:36:59.508Z',
+ 'value': '0.0022140838095238303'
+ },
+ {
+ 'time': '2017-06-04T23:37:59.508Z',
+ 'value': '0.0018592674425248847'
+ },
+ {
+ 'time': '2017-06-04T23:38:59.508Z',
+ 'value': '0.0020461969533657016'
+ },
+ {
+ 'time': '2017-06-04T23:39:59.508Z',
+ 'value': '0.0021593628571428543'
+ },
+ {
+ 'time': '2017-06-04T23:40:59.508Z',
+ 'value': '0.0024330682564928188'
+ },
+ {
+ 'time': '2017-06-04T23:41:59.508Z',
+ 'value': '0.0021501804779093174'
+ },
+ {
+ 'time': '2017-06-04T23:42:59.508Z',
+ 'value': '0.0025787493928397945'
+ },
+ {
+ 'time': '2017-06-04T23:43:59.508Z',
+ 'value': '0.002593657082448396'
+ },
+ {
+ 'time': '2017-06-04T23:44:59.508Z',
+ 'value': '0.0021316752380952306'
+ },
+ {
+ 'time': '2017-06-04T23:45:59.508Z',
+ 'value': '0.0026972905019952086'
+ },
+ {
+ 'time': '2017-06-04T23:46:59.508Z',
+ 'value': '0.002580250764292983'
+ },
+ {
+ 'time': '2017-06-04T23:47:59.508Z',
+ 'value': '0.00227103000000001'
+ },
+ {
+ 'time': '2017-06-04T23:48:59.508Z',
+ 'value': '0.0023678515647321146'
+ },
+ {
+ 'time': '2017-06-04T23:49:59.508Z',
+ 'value': '0.002371472857142866'
+ },
+ {
+ 'time': '2017-06-04T23:50:59.508Z',
+ 'value': '0.0026181353688500978'
+ },
+ {
+ 'time': '2017-06-04T23:51:59.508Z',
+ 'value': '0.0025609667711121217'
+ },
+ {
+ 'time': '2017-06-04T23:52:59.508Z',
+ 'value': '0.0027145308139922557'
+ },
+ {
+ 'time': '2017-06-04T23:53:59.508Z',
+ 'value': '0.0024249397613310512'
+ },
+ {
+ 'time': '2017-06-04T23:54:59.508Z',
+ 'value': '0.002399907142857147'
+ },
+ {
+ 'time': '2017-06-04T23:55:59.508Z',
+ 'value': '0.0024753357142857195'
+ },
+ {
+ 'time': '2017-06-04T23:56:59.508Z',
+ 'value': '0.0026179149325231575'
+ },
+ {
+ 'time': '2017-06-04T23:57:59.508Z',
+ 'value': '0.0024261340368186956'
+ },
+ {
+ 'time': '2017-06-04T23:58:59.508Z',
+ 'value': '0.0021061071428571517'
+ },
+ {
+ 'time': '2017-06-04T23:59:59.508Z',
+ 'value': '0.0024033971105037015'
+ },
+ {
+ 'time': '2017-06-05T00:00:59.508Z',
+ 'value': '0.0028287676190475956'
+ },
+ {
+ 'time': '2017-06-05T00:01:59.508Z',
+ 'value': '0.002499719050294778'
+ },
+ {
+ 'time': '2017-06-05T00:02:59.508Z',
+ 'value': '0.0026726102153353856'
+ },
+ {
+ 'time': '2017-06-05T00:03:59.508Z',
+ 'value': '0.00262582619047618'
+ },
+ {
+ 'time': '2017-06-05T00:04:59.508Z',
+ 'value': '0.002280473147363316'
+ },
+ {
+ 'time': '2017-06-05T00:05:59.508Z',
+ 'value': '0.002095581470652675'
+ },
+ {
+ 'time': '2017-06-05T00:06:59.508Z',
+ 'value': '0.002270768490828408'
+ },
+ {
+ 'time': '2017-06-05T00:07:59.508Z',
+ 'value': '0.002728577415023017'
+ },
+ {
+ 'time': '2017-06-05T00:08:59.508Z',
+ 'value': '0.002652512857142863'
+ },
+ {
+ 'time': '2017-06-05T00:09:59.508Z',
+ 'value': '0.0022781033924455674'
+ },
+ {
+ 'time': '2017-06-05T00:10:59.508Z',
+ 'value': '0.0025345038095238234'
+ },
+ {
+ 'time': '2017-06-05T00:11:59.508Z',
+ 'value': '0.002376050020000397'
+ },
+ {
+ 'time': '2017-06-05T00:12:59.508Z',
+ 'value': '0.002455068143506122'
+ },
+ {
+ 'time': '2017-06-05T00:13:59.508Z',
+ 'value': '0.002826705714285719'
+ },
+ {
+ 'time': '2017-06-05T00:14:59.508Z',
+ 'value': '0.002343833692070314'
+ },
+ {
+ 'time': '2017-06-05T00:15:59.508Z',
+ 'value': '0.00264853297122164'
+ },
+ {
+ 'time': '2017-06-05T00:16:59.508Z',
+ 'value': '0.0027656335117426257'
+ },
+ {
+ 'time': '2017-06-05T00:17:59.508Z',
+ 'value': '0.0025896543842439564'
+ },
+ {
+ 'time': '2017-06-05T00:18:59.508Z',
+ 'value': '0.002180053237081201'
+ },
+ {
+ 'time': '2017-06-05T00:19:59.508Z',
+ 'value': '0.002475245002333342'
+ },
+ {
+ 'time': '2017-06-05T00:20:59.508Z',
+ 'value': '0.0027559767805101065'
+ },
+ {
+ 'time': '2017-06-05T00:21:59.508Z',
+ 'value': '0.0022294836141296607'
+ },
+ {
+ 'time': '2017-06-05T00:22:59.508Z',
+ 'value': '0.0021383590476190643'
+ },
+ {
+ 'time': '2017-06-05T00:23:59.508Z',
+ 'value': '0.002085417956361494'
+ },
+ {
+ 'time': '2017-06-05T00:24:59.508Z',
+ 'value': '0.0024140319047619013'
+ },
+ {
+ 'time': '2017-06-05T00:25:59.508Z',
+ 'value': '0.0024513114285714304'
+ },
+ {
+ 'time': '2017-06-05T00:26:59.508Z',
+ 'value': '0.0026932152380952446'
+ },
+ {
+ 'time': '2017-06-05T00:27:59.508Z',
+ 'value': '0.0022656844350898517'
+ },
+ {
+ 'time': '2017-06-05T00:28:59.508Z',
+ 'value': '0.0024483785714285704'
+ },
+ {
+ 'time': '2017-06-05T00:29:59.508Z',
+ 'value': '0.002559505804817207'
+ },
+ {
+ 'time': '2017-06-05T00:30:59.508Z',
+ 'value': '0.0019485681088751649'
+ },
+ {
+ 'time': '2017-06-05T00:31:59.508Z',
+ 'value': '0.00228367984456996'
+ },
+ {
+ 'time': '2017-06-05T00:32:59.508Z',
+ 'value': '0.002522149047619049'
+ },
+ {
+ 'time': '2017-06-05T00:33:59.508Z',
+ 'value': '0.0026860117715406737'
+ },
+ {
+ 'time': '2017-06-05T00:34:59.508Z',
+ 'value': '0.002679669523809523'
+ },
+ {
+ 'time': '2017-06-05T00:35:59.508Z',
+ 'value': '0.0022201920970675937'
+ },
+ {
+ 'time': '2017-06-05T00:36:59.508Z',
+ 'value': '0.0022917647619047615'
+ },
+ {
+ 'time': '2017-06-05T00:37:59.508Z',
+ 'value': '0.0021774059294673576'
+ },
+ {
+ 'time': '2017-06-05T00:38:59.508Z',
+ 'value': '0.0024637766666666763'
+ },
+ {
+ 'time': '2017-06-05T00:39:59.508Z',
+ 'value': '0.002470468290174195'
+ },
+ {
+ 'time': '2017-06-05T00:40:59.508Z',
+ 'value': '0.0022188616082057812'
+ },
+ {
+ 'time': '2017-06-05T00:41:59.508Z',
+ 'value': '0.002421840744373875'
+ },
+ {
+ 'time': '2017-06-05T00:42:59.508Z',
+ 'value': '0.0023918266666666547'
+ },
+ {
+ 'time': '2017-06-05T00:43:59.508Z',
+ 'value': '0.002195743809523809'
+ },
+ {
+ 'time': '2017-06-05T00:44:59.508Z',
+ 'value': '0.0025514828571428687'
+ },
+ {
+ 'time': '2017-06-05T00:45:59.508Z',
+ 'value': '0.0027981709349612694'
+ },
+ {
+ 'time': '2017-06-05T00:46:59.508Z',
+ 'value': '0.002557977142857146'
+ },
+ {
+ 'time': '2017-06-05T00:47:59.508Z',
+ 'value': '0.002213244285714286'
+ },
+ {
+ 'time': '2017-06-05T00:48:59.508Z',
+ 'value': '0.0025706738095238046'
+ },
+ {
+ 'time': '2017-06-05T00:49:59.508Z',
+ 'value': '0.002210976666666671'
+ },
+ {
+ 'time': '2017-06-05T00:50:59.508Z',
+ 'value': '0.002055377091646749'
+ },
+ {
+ 'time': '2017-06-05T00:51:59.508Z',
+ 'value': '0.002308368095238119'
+ },
+ {
+ 'time': '2017-06-05T00:52:59.508Z',
+ 'value': '0.0024687939885141615'
+ },
+ {
+ 'time': '2017-06-05T00:53:59.508Z',
+ 'value': '0.002563018571428578'
+ },
+ {
+ 'time': '2017-06-05T00:54:59.508Z',
+ 'value': '0.00240563291078959'
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ 'title': 'Memory usage',
+ 'weight': 1,
+ 'y_label': 'Values',
+ 'queries': [
+ {
+ 'query_range': 'avg(container_memory_usage_bytes{%{environment_filter}}) / 2^20',
+ 'label': 'Container memory',
+ 'unit': 'MiB',
+ 'result': [
+ {
+ 'metric': {
+
+ },
+ 'values': [
+ {
+ 'time': '2017-06-04T21:22:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:23:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:24:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:25:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:26:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:27:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:28:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:29:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:30:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:31:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:32:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:33:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:34:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:35:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:36:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:37:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:38:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:39:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:40:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:41:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:42:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:43:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:44:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:45:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:46:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:47:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:48:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:49:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:50:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:51:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:52:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:53:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:54:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:55:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:56:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:57:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:58:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T21:59:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:00:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:01:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:02:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:03:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:04:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:05:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:06:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:07:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:08:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:09:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:10:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:11:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:12:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:13:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:14:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:15:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:16:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:17:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:18:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:19:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:20:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:21:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:22:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:23:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:24:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:25:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:26:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:27:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:28:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:29:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:30:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:31:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:32:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:33:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:34:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:35:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:36:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:37:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:38:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:39:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:40:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:41:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:42:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:43:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:44:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:45:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:46:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:47:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:48:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:49:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:50:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:51:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:52:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:53:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:54:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:55:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:56:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:57:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:58:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T22:59:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:00:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:01:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:02:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:03:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:04:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:05:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:06:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:07:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:08:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:09:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:10:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:11:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:12:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:13:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:14:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:15:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:16:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:17:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:18:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:19:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:20:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:21:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:22:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:23:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:24:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:25:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:26:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:27:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:28:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:29:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:30:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:31:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:32:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:33:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:34:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:35:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:36:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:37:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:38:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:39:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:40:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:41:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:42:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:43:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:44:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:45:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:46:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:47:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:48:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:49:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:50:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:51:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:52:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:53:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:54:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:55:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:56:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:57:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:58:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-04T23:59:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:00:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:01:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:02:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:03:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:04:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:05:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:06:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:07:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:08:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:09:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:10:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:11:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:12:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:13:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:14:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:15:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:16:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:17:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:18:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:19:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:20:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:21:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:22:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:23:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:24:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:25:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:26:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:27:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:28:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:29:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:30:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:31:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:32:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:33:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:34:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:35:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:36:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:37:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:38:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:39:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:40:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:41:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:42:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:43:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:44:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:45:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:46:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:47:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:48:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:49:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:50:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:51:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:52:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:53:59.508Z',
+ 'value': '15.0859375'
+ },
+ {
+ 'time': '2017-06-05T00:54:59.508Z',
+ 'value': '15.0859375'
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+];
+
+export function MonitorMockInterceptor(request, next) {
+ const body = responseMockData[request.method.toUpperCase()][request.url];
+
+ next(request.respondWith(JSON.stringify(body), {
+ status: 200,
+ }));
+}
diff --git a/spec/javascripts/monitoring/monitoring_column_spec.js b/spec/javascripts/monitoring/monitoring_column_spec.js
new file mode 100644
index 00000000000..c423024dce0
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_column_spec.js
@@ -0,0 +1,109 @@
+import Vue from 'vue';
+import _ from 'underscore';
+import MonitoringColumn from '~/monitoring/components/monitoring_column.vue';
+import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins';
+import eventHub from '~/monitoring/event_hub';
+import { deploymentData, singleRowMetrics } from './mock_data';
+
+const createComponent = (propsData) => {
+ const Component = Vue.extend(MonitoringColumn);
+
+ return new Component({
+ propsData,
+ }).$mount();
+};
+
+describe('MonitoringColumn', () => {
+ beforeEach(() => {
+ spyOn(MonitoringMixins.methods, 'formatDeployments').and.callFake(function fakeFormat() {
+ return {};
+ });
+ });
+
+ it('has a title', () => {
+ const component = createComponent({
+ columnData: singleRowMetrics[0],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(component.columnData.title);
+ });
+
+ it('creates a path for the line and area of the graph', (done) => {
+ const component = createComponent({
+ columnData: singleRowMetrics[0],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ Vue.nextTick(() => {
+ expect(component.area).toBeDefined();
+ expect(component.line).toBeDefined();
+ expect(typeof component.area).toEqual('string');
+ expect(typeof component.line).toEqual('string');
+ expect(_.isFunction(component.xScale)).toBe(true);
+ expect(_.isFunction(component.yScale)).toBe(true);
+ done();
+ });
+ });
+
+ describe('Computed props', () => {
+ it('axisTransform translates an element Y position depending of its height', () => {
+ const component = createComponent({
+ columnData: singleRowMetrics[0],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ const transformedHeight = `${component.graphHeight - 100}`;
+ expect(component.axisTransform.indexOf(transformedHeight))
+ .not.toEqual(-1);
+ });
+
+ it('outterViewBox gets a width and height property based on the DOM size of the element', () => {
+ const component = createComponent({
+ columnData: singleRowMetrics[0],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ const viewBoxArray = component.outterViewBox.split(' ');
+ expect(typeof component.outterViewBox).toEqual('string');
+ expect(viewBoxArray[2]).toEqual(component.graphWidth.toString());
+ expect(viewBoxArray[3]).toEqual(component.graphHeight.toString());
+ });
+ });
+
+ it('sends an event to the eventhub when it has finished resizing', (done) => {
+ const component = createComponent({
+ columnData: singleRowMetrics[0],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ });
+ spyOn(eventHub, '$emit');
+
+ component.updateAspectRatio = true;
+ Vue.nextTick(() => {
+ expect(eventHub.$emit).toHaveBeenCalled();
+ done();
+ });
+ });
+
+ it('has a title for the y-axis and the chart legend that comes from the backend', () => {
+ const component = createComponent({
+ columnData: singleRowMetrics[0],
+ classType: 'col-md-6',
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ expect(component.yAxisLabel).toEqual(component.columnData.y_label);
+ expect(component.legendTitle).toEqual(component.columnData.queries[0].label);
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_deployment_spec.js b/spec/javascripts/monitoring/monitoring_deployment_spec.js
new file mode 100644
index 00000000000..5cc5b514824
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_deployment_spec.js
@@ -0,0 +1,137 @@
+import Vue from 'vue';
+import MonitoringState from '~/monitoring/components/monitoring_deployment.vue';
+import { deploymentData } from './mock_data';
+
+const createComponent = (propsData) => {
+ const Component = Vue.extend(MonitoringState);
+
+ return new Component({
+ propsData,
+ }).$mount();
+};
+
+describe('MonitoringDeployment', () => {
+ const reducedDeploymentData = [deploymentData[0]];
+ reducedDeploymentData[0].ref = reducedDeploymentData[0].ref.name;
+ reducedDeploymentData[0].xPos = 10;
+ reducedDeploymentData[0].time = new Date(reducedDeploymentData[0].created_at);
+ describe('Methods', () => {
+ it('refText shows the ref when a tag is available', () => {
+ reducedDeploymentData[0].tag = '1.0';
+ const component = createComponent({
+ showDeployInfo: false,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(
+ component.refText(reducedDeploymentData[0]),
+ ).toEqual(reducedDeploymentData[0].ref);
+ });
+
+ it('refText shows the sha when no tag is available', () => {
+ reducedDeploymentData[0].tag = null;
+ const component = createComponent({
+ showDeployInfo: false,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(
+ component.refText(reducedDeploymentData[0]),
+ ).toContain('f5bcd1');
+ });
+
+ it('nameDeploymentClass creates a class with the prefix deploy-info-', () => {
+ const component = createComponent({
+ showDeployInfo: false,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(
+ component.nameDeploymentClass(reducedDeploymentData[0]),
+ ).toContain('deploy-info');
+ });
+
+ it('transformDeploymentGroup translates an available deployment', () => {
+ const component = createComponent({
+ showDeployInfo: false,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(
+ component.transformDeploymentGroup(reducedDeploymentData[0]),
+ ).toContain('translate(11, 20)');
+ });
+
+ it('hides the deployment flag', () => {
+ reducedDeploymentData[0].showDeploymentFlag = false;
+ const component = createComponent({
+ showDeployInfo: true,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(component.$el.querySelector('.js-deploy-info-box')).toBeNull();
+ });
+
+ it('shows the deployment flag', () => {
+ reducedDeploymentData[0].showDeploymentFlag = true;
+ const component = createComponent({
+ showDeployInfo: true,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(
+ component.$el.querySelector('.js-deploy-info-box').style.display,
+ ).not.toEqual('display: none;');
+ });
+
+ it('shows the refText inside a text element with the deploy-info-text class', () => {
+ reducedDeploymentData[0].showDeploymentFlag = true;
+ const component = createComponent({
+ showDeployInfo: true,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(
+ component.$el.querySelector('.deploy-info-text').firstChild.nodeValue.trim(),
+ ).toEqual(component.refText(reducedDeploymentData[0]));
+ });
+
+ it('should contain a hidden gradient', () => {
+ const component = createComponent({
+ showDeployInfo: true,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(component.$el.querySelector('#shadow-gradient')).not.toBeNull();
+ });
+
+ describe('Computed props', () => {
+ it('calculatedHeight', () => {
+ const component = createComponent({
+ showDeployInfo: true,
+ deploymentData: reducedDeploymentData,
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(component.calculatedHeight).toEqual(180);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_flag_spec.js b/spec/javascripts/monitoring/monitoring_flag_spec.js
new file mode 100644
index 00000000000..3861a95ff07
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_flag_spec.js
@@ -0,0 +1,76 @@
+import Vue from 'vue';
+import MonitoringFlag from '~/monitoring/components/monitoring_flag.vue';
+
+const createComponent = (propsData) => {
+ const Component = Vue.extend(MonitoringFlag);
+
+ return new Component({
+ propsData,
+ }).$mount();
+};
+
+function getCoordinate(component, selector, coordinate) {
+ const coordinateVal = component.$el.querySelector(selector).getAttribute(coordinate);
+ return parseInt(coordinateVal, 10);
+}
+
+describe('MonitoringFlag', () => {
+ it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => {
+ const component = createComponent({
+ currentXCoordinate: 200,
+ currentYCoordinate: 100,
+ currentFlagPosition: 100,
+ currentData: {
+ time: new Date('2017-06-04T18:17:33.501Z'),
+ value: '1.49609375',
+ },
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(getCoordinate(component, '.selected-metric-line', 'x1'))
+ .toEqual(component.currentXCoordinate);
+ expect(getCoordinate(component, '.selected-metric-line', 'x2'))
+ .toEqual(component.currentXCoordinate);
+ expect(getCoordinate(component, '.circle-metric', 'cx'))
+ .toEqual(component.currentXCoordinate);
+ expect(getCoordinate(component, '.circle-metric', 'cy'))
+ .toEqual(component.currentYCoordinate);
+ });
+
+ it('has a SVG with the class rect-text-metric at the currentFlagPosition', () => {
+ const component = createComponent({
+ currentXCoordinate: 200,
+ currentYCoordinate: 100,
+ currentFlagPosition: 100,
+ currentData: {
+ time: new Date('2017-06-04T18:17:33.501Z'),
+ value: '1.49609375',
+ },
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ const svg = component.$el.querySelector('.rect-text-metric');
+ expect(svg.tagName).toEqual('svg');
+ expect(parseInt(svg.getAttribute('x'), 10)).toEqual(component.currentFlagPosition);
+ });
+
+ describe('Computed props', () => {
+ it('calculatedHeight', () => {
+ const component = createComponent({
+ currentXCoordinate: 200,
+ currentYCoordinate: 100,
+ currentFlagPosition: 100,
+ currentData: {
+ time: new Date('2017-06-04T18:17:33.501Z'),
+ value: '1.49609375',
+ },
+ graphHeight: 300,
+ graphHeightOffset: 120,
+ });
+
+ expect(component.calculatedHeight).toEqual(180);
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_legends_spec.js b/spec/javascripts/monitoring/monitoring_legends_spec.js
new file mode 100644
index 00000000000..4c69b81e650
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_legends_spec.js
@@ -0,0 +1,111 @@
+import Vue from 'vue';
+import MonitoringLegends from '~/monitoring/components/monitoring_legends.vue';
+import measurements from '~/monitoring/utils/measurements';
+
+const createComponent = (propsData) => {
+ const Component = Vue.extend(MonitoringLegends);
+
+ return new Component({
+ propsData,
+ }).$mount();
+};
+
+function getTextFromNode(component, selector) {
+ return component.$el.querySelector(selector).firstChild.nodeValue.trim();
+}
+
+describe('MonitoringLegends', () => {
+ describe('Computed props', () => {
+ it('textTransform', () => {
+ const component = createComponent({
+ graphWidth: 500,
+ graphHeight: 300,
+ margin: measurements.large.margin,
+ measurements: measurements.large,
+ areaColorRgb: '#f0f0f0',
+ legendTitle: 'Title',
+ yAxisLabel: 'Values',
+ metricUsage: 'Value',
+ });
+
+ expect(component.textTransform).toContain('translate(15, 120) rotate(-90)');
+ });
+
+ it('xPosition', () => {
+ const component = createComponent({
+ graphWidth: 500,
+ graphHeight: 300,
+ margin: measurements.large.margin,
+ measurements: measurements.large,
+ areaColorRgb: '#f0f0f0',
+ legendTitle: 'Title',
+ yAxisLabel: 'Values',
+ metricUsage: 'Value',
+ });
+
+ expect(component.xPosition).toEqual(180);
+ });
+
+ it('yPosition', () => {
+ const component = createComponent({
+ graphWidth: 500,
+ graphHeight: 300,
+ margin: measurements.large.margin,
+ measurements: measurements.large,
+ areaColorRgb: '#f0f0f0',
+ legendTitle: 'Title',
+ yAxisLabel: 'Values',
+ metricUsage: 'Value',
+ });
+
+ expect(component.yPosition).toEqual(240);
+ });
+
+ it('rectTransform', () => {
+ const component = createComponent({
+ graphWidth: 500,
+ graphHeight: 300,
+ margin: measurements.large.margin,
+ measurements: measurements.large,
+ areaColorRgb: '#f0f0f0',
+ legendTitle: 'Title',
+ yAxisLabel: 'Values',
+ metricUsage: 'Value',
+ });
+
+ expect(component.rectTransform).toContain('translate(0, 120) rotate(-90)');
+ });
+ });
+
+ it('has 2 rect-axis-text rect svg elements', () => {
+ const component = createComponent({
+ graphWidth: 500,
+ graphHeight: 300,
+ margin: measurements.large.margin,
+ measurements: measurements.large,
+ areaColorRgb: '#f0f0f0',
+ legendTitle: 'Title',
+ yAxisLabel: 'Values',
+ metricUsage: 'Value',
+ });
+
+ expect(component.$el.querySelectorAll('.rect-axis-text').length).toEqual(2);
+ });
+
+ it('contains text to signal the usage, title and time', () => {
+ const component = createComponent({
+ graphWidth: 500,
+ graphHeight: 300,
+ margin: measurements.large.margin,
+ measurements: measurements.large,
+ areaColorRgb: '#f0f0f0',
+ legendTitle: 'Title',
+ yAxisLabel: 'Values',
+ metricUsage: 'Value',
+ });
+
+ expect(getTextFromNode(component, '.text-metric-title')).toEqual(component.legendTitle);
+ expect(getTextFromNode(component, '.text-metric-usage')).toEqual(component.metricUsage);
+ expect(getTextFromNode(component, '.label-axis-text')).toEqual(component.yAxisLabel);
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_row_spec.js b/spec/javascripts/monitoring/monitoring_row_spec.js
new file mode 100644
index 00000000000..a82480e8342
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_row_spec.js
@@ -0,0 +1,57 @@
+import Vue from 'vue';
+import MonitoringRow from '~/monitoring/components/monitoring_row.vue';
+import { deploymentData, singleRowMetrics } from './mock_data';
+
+const createComponent = (propsData) => {
+ const Component = Vue.extend(MonitoringRow);
+
+ return new Component({
+ propsData,
+ }).$mount();
+};
+
+describe('MonitoringRow', () => {
+ describe('Computed props', () => {
+ it('bootstrapClass is set to col-md-6 when rowData is higher/equal to 2', () => {
+ const component = createComponent({
+ rowData: singleRowMetrics,
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ expect(component.bootstrapClass).toEqual('col-md-6');
+ });
+
+ it('bootstrapClass is set to col-md-12 when rowData is lower than 2', () => {
+ const component = createComponent({
+ rowData: [singleRowMetrics[0]],
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ expect(component.bootstrapClass).toEqual('col-md-12');
+ });
+ });
+
+ it('has one column', () => {
+ const component = createComponent({
+ rowData: singleRowMetrics,
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ expect(component.$el.querySelectorAll('.prometheus-svg-container').length)
+ .toEqual(component.rowData.length);
+ });
+
+ it('has two columns', () => {
+ const component = createComponent({
+ rowData: singleRowMetrics,
+ updateAspectRatio: false,
+ deploymentData,
+ });
+
+ expect(component.$el.querySelectorAll('.col-md-6').length)
+ .toEqual(component.rowData.length);
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_spec.js b/spec/javascripts/monitoring/monitoring_spec.js
new file mode 100644
index 00000000000..6c7b691baa4
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_spec.js
@@ -0,0 +1,49 @@
+import Vue from 'vue';
+import Monitoring from '~/monitoring/components/monitoring.vue';
+import { MonitorMockInterceptor } from './mock_data';
+
+describe('Monitoring', () => {
+ const fixtureName = 'environments/metrics/metrics.html.raw';
+ let MonitoringComponent;
+ let component;
+ preloadFixtures(fixtureName);
+
+ beforeEach(() => {
+ loadFixtures(fixtureName);
+ MonitoringComponent = Vue.extend(Monitoring);
+ });
+
+ describe('no metrics are available yet', () => {
+ it('shows a getting started empty state when no metrics are present', () => {
+ component = new MonitoringComponent({
+ el: document.querySelector('#prometheus-graphs'),
+ });
+
+ component.$mount();
+ expect(component.$el.querySelector('#prometheus-graphs')).toBe(null);
+ expect(component.state).toEqual('gettingStarted');
+ });
+ });
+
+ describe('requests information to the server', () => {
+ beforeEach(() => {
+ document.querySelector('#prometheus-graphs').setAttribute('data-has-metrics', 'true');
+ Vue.http.interceptors.push(MonitorMockInterceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, MonitorMockInterceptor);
+ });
+
+ it('shows up a loading state', (done) => {
+ component = new MonitoringComponent({
+ el: document.querySelector('#prometheus-graphs'),
+ });
+ component.$mount();
+ Vue.nextTick(() => {
+ expect(component.state).toEqual('loading');
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_state_spec.js b/spec/javascripts/monitoring/monitoring_state_spec.js
new file mode 100644
index 00000000000..4c0c558502f
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_state_spec.js
@@ -0,0 +1,110 @@
+import Vue from 'vue';
+import MonitoringState from '~/monitoring/components/monitoring_state.vue';
+import { statePaths } from './mock_data';
+
+const createComponent = (propsData) => {
+ const Component = Vue.extend(MonitoringState);
+
+ return new Component({
+ propsData,
+ }).$mount();
+};
+
+function getTextFromNode(component, selector) {
+ return component.$el.querySelector(selector).firstChild.nodeValue.trim();
+}
+
+describe('MonitoringState', () => {
+ describe('Computed props', () => {
+ it('currentState', () => {
+ const component = createComponent({
+ selectedState: 'gettingStarted',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.currentState).toBe(component.states.gettingStarted);
+ });
+
+ it('buttonPath returns settings path for the state "gettingStarted"', () => {
+ const component = createComponent({
+ selectedState: 'gettingStarted',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.buttonPath).toEqual(statePaths.settingsPath);
+ expect(component.buttonPath).not.toEqual(statePaths.documentationPath);
+ });
+
+ it('buttonPath returns documentation path for any of the other states', () => {
+ const component = createComponent({
+ selectedState: 'loading',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.buttonPath).toEqual(statePaths.documentationPath);
+ expect(component.buttonPath).not.toEqual(statePaths.settingsPath);
+ });
+
+ it('showButtonDescription returns a description with a link for the unableToConnect state', () => {
+ const component = createComponent({
+ selectedState: 'unableToConnect',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.showButtonDescription).toEqual(true);
+ });
+
+ it('showButtonDescription returns the description without a link for any other state', () => {
+ const component = createComponent({
+ selectedState: 'loading',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.showButtonDescription).toEqual(false);
+ });
+ });
+
+ it('should show the gettingStarted state', () => {
+ const component = createComponent({
+ selectedState: 'gettingStarted',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.$el.querySelector('svg')).toBeDefined();
+ expect(getTextFromNode(component, '.state-title')).toEqual(component.states.gettingStarted.title);
+ expect(getTextFromNode(component, '.state-description')).toEqual(component.states.gettingStarted.description);
+ expect(getTextFromNode(component, '.btn-success')).toEqual(component.states.gettingStarted.buttonText);
+ });
+
+ it('should show the loading state', () => {
+ const component = createComponent({
+ selectedState: 'loading',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.$el.querySelector('svg')).toBeDefined();
+ expect(getTextFromNode(component, '.state-title')).toEqual(component.states.loading.title);
+ expect(getTextFromNode(component, '.state-description')).toEqual(component.states.loading.description);
+ expect(getTextFromNode(component, '.btn-success')).toEqual(component.states.loading.buttonText);
+ });
+
+ it('should show the unableToConnect state', () => {
+ const component = createComponent({
+ selectedState: 'unableToConnect',
+ settingsPath: statePaths.settingsPath,
+ documentationPath: statePaths.documentationPath,
+ });
+
+ expect(component.$el.querySelector('svg')).toBeDefined();
+ expect(getTextFromNode(component, '.state-title')).toEqual(component.states.unableToConnect.title);
+ expect(component.$el.querySelector('.state-description a')).toBeDefined();
+ expect(getTextFromNode(component, '.btn-success')).toEqual(component.states.unableToConnect.buttonText);
+ });
+});
diff --git a/spec/javascripts/monitoring/monitoring_store_spec.js b/spec/javascripts/monitoring/monitoring_store_spec.js
new file mode 100644
index 00000000000..20c1e6a0005
--- /dev/null
+++ b/spec/javascripts/monitoring/monitoring_store_spec.js
@@ -0,0 +1,24 @@
+import MonitoringStore from '~/monitoring/stores/monitoring_store';
+import MonitoringMock, { deploymentData } from './mock_data';
+
+describe('MonitoringStore', () => {
+ this.store = new MonitoringStore();
+ this.store.storeMetrics(MonitoringMock.data);
+
+ it('contains one group that contains two queries sorted by priority in one row', () => {
+ expect(this.store.groups).toBeDefined();
+ expect(this.store.groups.length).toEqual(1);
+ expect(this.store.groups[0].metrics.length).toEqual(1);
+ });
+
+ it('gets the metrics count for every group', () => {
+ expect(this.store.getMetricsCount()).toEqual(2);
+ });
+
+ it('contains deployment data', () => {
+ this.store.storeDeploymentData(deploymentData);
+ expect(this.store.deploymentData).toBeDefined();
+ expect(this.store.deploymentData.length).toEqual(3);
+ expect(typeof this.store.deploymentData[0]).toEqual('object');
+ });
+});
diff --git a/spec/javascripts/monitoring/prometheus_graph_spec.js b/spec/javascripts/monitoring/prometheus_graph_spec.js
deleted file mode 100644
index 25578bf1c6e..00000000000
--- a/spec/javascripts/monitoring/prometheus_graph_spec.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import 'jquery';
-import PrometheusGraph from '~/monitoring/prometheus_graph';
-import { prometheusMockData } from './prometheus_mock_data';
-
-describe('PrometheusGraph', () => {
- const fixtureName = 'environments/metrics/metrics.html.raw';
- const prometheusGraphContainer = '.prometheus-graph';
- const prometheusGraphContents = `${prometheusGraphContainer}[graph-type=cpu_values]`;
-
- preloadFixtures(fixtureName);
-
- beforeEach(() => {
- loadFixtures(fixtureName);
- $('.prometheus-container').data('has-metrics', 'true');
- this.prometheusGraph = new PrometheusGraph();
- const self = this;
- const fakeInit = (metricsResponse) => {
- self.prometheusGraph.transformData(metricsResponse);
- self.prometheusGraph.createGraph();
- };
- spyOn(this.prometheusGraph, 'init').and.callFake(fakeInit);
- });
-
- it('initializes graph properties', () => {
- // Test for the measurements
- expect(this.prometheusGraph.margin).toBeDefined();
- expect(this.prometheusGraph.marginLabelContainer).toBeDefined();
- expect(this.prometheusGraph.originalWidth).toBeDefined();
- expect(this.prometheusGraph.originalHeight).toBeDefined();
- expect(this.prometheusGraph.height).toBeDefined();
- expect(this.prometheusGraph.width).toBeDefined();
- expect(this.prometheusGraph.backOffRequestCounter).toBeDefined();
- // Test for the graph properties (colors, radius, etc.)
- expect(this.prometheusGraph.graphSpecificProperties).toBeDefined();
- expect(this.prometheusGraph.commonGraphProperties).toBeDefined();
- });
-
- it('transforms the data', () => {
- this.prometheusGraph.init(prometheusMockData.metrics);
- Object.keys(this.prometheusGraph.graphSpecificProperties, (key) => {
- const graphProps = this.prometheusGraph.graphSpecificProperties[key];
- expect(graphProps.data).toBeDefined();
- expect(graphProps.data.length).toBe(121);
- });
- });
-
- it('creates two graphs', () => {
- this.prometheusGraph.init(prometheusMockData.metrics);
- expect($(prometheusGraphContainer).length).toBe(2);
- });
-
- describe('Graph contents', () => {
- beforeEach(() => {
- this.prometheusGraph.init(prometheusMockData.metrics);
- });
-
- it('has axis, an area, a line and a overlay', () => {
- const $graphContainer = $(prometheusGraphContents).find('.x-axis').parent();
- expect($graphContainer.find('.x-axis')).toBeDefined();
- expect($graphContainer.find('.y-axis')).toBeDefined();
- expect($graphContainer.find('.prometheus-graph-overlay')).toBeDefined();
- expect($graphContainer.find('.metric-line')).toBeDefined();
- expect($graphContainer.find('.metric-area')).toBeDefined();
- });
-
- it('has legends, labels and an extra axis that labels the metrics', () => {
- const $prometheusGraphContents = $(prometheusGraphContents);
- const $axisLabelContainer = $(prometheusGraphContents).find('.label-x-axis-line').parent();
- expect($prometheusGraphContents.find('.label-x-axis-line')).toBeDefined();
- expect($prometheusGraphContents.find('.label-y-axis-line')).toBeDefined();
- expect($prometheusGraphContents.find('.label-axis-text')).toBeDefined();
- expect($prometheusGraphContents.find('.rect-axis-text')).toBeDefined();
- expect($axisLabelContainer.find('rect').length).toBe(3);
- expect($axisLabelContainer.find('text').length).toBe(4);
- });
- });
-});
-
-describe('PrometheusGraphs UX states', () => {
- const fixtureName = 'environments/metrics/metrics.html.raw';
- preloadFixtures(fixtureName);
-
- beforeEach(() => {
- loadFixtures(fixtureName);
- this.prometheusGraph = new PrometheusGraph();
- });
-
- it('shows a specified state', () => {
- this.prometheusGraph.state = '.js-getting-started';
- this.prometheusGraph.updateState();
- const $state = $('.js-getting-started');
- expect($state).toBeDefined();
- expect($('.state-title', $state)).toBeDefined();
- expect($('.state-svg', $state)).toBeDefined();
- expect($('.state-description', $state)).toBeDefined();
- expect($('.state-button', $state)).toBeDefined();
- });
-});
diff --git a/spec/javascripts/monitoring/prometheus_mock_data.js b/spec/javascripts/monitoring/prometheus_mock_data.js
deleted file mode 100644
index 1cdc14faaa8..00000000000
--- a/spec/javascripts/monitoring/prometheus_mock_data.js
+++ /dev/null
@@ -1,1014 +0,0 @@
-/* eslint-disable import/prefer-default-export*/
-export const prometheusMockData = {
- status: 200,
- metrics: {
- success: true,
- metrics: {
- memory_values: [
- {
- metric: {
- },
- values: [
- [
- 1488462917.256,
- '10.12890625',
- ],
- [
- 1488462977.256,
- '10.140625',
- ],
- [
- 1488463037.256,
- '10.140625',
- ],
- [
- 1488463097.256,
- '10.14453125',
- ],
- [
- 1488463157.256,
- '10.1484375',
- ],
- [
- 1488463217.256,
- '10.15625',
- ],
- [
- 1488463277.256,
- '10.15625',
- ],
- [
- 1488463337.256,
- '10.15625',
- ],
- [
- 1488463397.256,
- '10.1640625',
- ],
- [
- 1488463457.256,
- '10.171875',
- ],
- [
- 1488463517.256,
- '10.171875',
- ],
- [
- 1488463577.256,
- '10.171875',
- ],
- [
- 1488463637.256,
- '10.18359375',
- ],
- [
- 1488463697.256,
- '10.1953125',
- ],
- [
- 1488463757.256,
- '10.203125',
- ],
- [
- 1488463817.256,
- '10.20703125',
- ],
- [
- 1488463877.256,
- '10.20703125',
- ],
- [
- 1488463937.256,
- '10.20703125',
- ],
- [
- 1488463997.256,
- '10.20703125',
- ],
- [
- 1488464057.256,
- '10.2109375',
- ],
- [
- 1488464117.256,
- '10.2109375',
- ],
- [
- 1488464177.256,
- '10.2109375',
- ],
- [
- 1488464237.256,
- '10.2109375',
- ],
- [
- 1488464297.256,
- '10.21484375',
- ],
- [
- 1488464357.256,
- '10.22265625',
- ],
- [
- 1488464417.256,
- '10.22265625',
- ],
- [
- 1488464477.256,
- '10.2265625',
- ],
- [
- 1488464537.256,
- '10.23046875',
- ],
- [
- 1488464597.256,
- '10.23046875',
- ],
- [
- 1488464657.256,
- '10.234375',
- ],
- [
- 1488464717.256,
- '10.234375',
- ],
- [
- 1488464777.256,
- '10.234375',
- ],
- [
- 1488464837.256,
- '10.234375',
- ],
- [
- 1488464897.256,
- '10.234375',
- ],
- [
- 1488464957.256,
- '10.234375',
- ],
- [
- 1488465017.256,
- '10.23828125',
- ],
- [
- 1488465077.256,
- '10.23828125',
- ],
- [
- 1488465137.256,
- '10.2421875',
- ],
- [
- 1488465197.256,
- '10.2421875',
- ],
- [
- 1488465257.256,
- '10.2421875',
- ],
- [
- 1488465317.256,
- '10.2421875',
- ],
- [
- 1488465377.256,
- '10.2421875',
- ],
- [
- 1488465437.256,
- '10.2421875',
- ],
- [
- 1488465497.256,
- '10.2421875',
- ],
- [
- 1488465557.256,
- '10.2421875',
- ],
- [
- 1488465617.256,
- '10.2421875',
- ],
- [
- 1488465677.256,
- '10.2421875',
- ],
- [
- 1488465737.256,
- '10.2421875',
- ],
- [
- 1488465797.256,
- '10.24609375',
- ],
- [
- 1488465857.256,
- '10.25',
- ],
- [
- 1488465917.256,
- '10.25390625',
- ],
- [
- 1488465977.256,
- '9.98828125',
- ],
- [
- 1488466037.256,
- '9.9921875',
- ],
- [
- 1488466097.256,
- '9.9921875',
- ],
- [
- 1488466157.256,
- '9.99609375',
- ],
- [
- 1488466217.256,
- '10',
- ],
- [
- 1488466277.256,
- '10.00390625',
- ],
- [
- 1488466337.256,
- '10.0078125',
- ],
- [
- 1488466397.256,
- '10.01171875',
- ],
- [
- 1488466457.256,
- '10.0234375',
- ],
- [
- 1488466517.256,
- '10.02734375',
- ],
- [
- 1488466577.256,
- '10.02734375',
- ],
- [
- 1488466637.256,
- '10.03125',
- ],
- [
- 1488466697.256,
- '10.03125',
- ],
- [
- 1488466757.256,
- '10.03125',
- ],
- [
- 1488466817.256,
- '10.03125',
- ],
- [
- 1488466877.256,
- '10.03125',
- ],
- [
- 1488466937.256,
- '10.03125',
- ],
- [
- 1488466997.256,
- '10.03125',
- ],
- [
- 1488467057.256,
- '10.0390625',
- ],
- [
- 1488467117.256,
- '10.0390625',
- ],
- [
- 1488467177.256,
- '10.04296875',
- ],
- [
- 1488467237.256,
- '10.05078125',
- ],
- [
- 1488467297.256,
- '10.05859375',
- ],
- [
- 1488467357.256,
- '10.06640625',
- ],
- [
- 1488467417.256,
- '10.06640625',
- ],
- [
- 1488467477.256,
- '10.0703125',
- ],
- [
- 1488467537.256,
- '10.07421875',
- ],
- [
- 1488467597.256,
- '10.0859375',
- ],
- [
- 1488467657.256,
- '10.0859375',
- ],
- [
- 1488467717.256,
- '10.09765625',
- ],
- [
- 1488467777.256,
- '10.1015625',
- ],
- [
- 1488467837.256,
- '10.10546875',
- ],
- [
- 1488467897.256,
- '10.10546875',
- ],
- [
- 1488467957.256,
- '10.125',
- ],
- [
- 1488468017.256,
- '10.13671875',
- ],
- [
- 1488468077.256,
- '10.1484375',
- ],
- [
- 1488468137.256,
- '10.15625',
- ],
- [
- 1488468197.256,
- '10.16796875',
- ],
- [
- 1488468257.256,
- '10.171875',
- ],
- [
- 1488468317.256,
- '10.171875',
- ],
- [
- 1488468377.256,
- '10.171875',
- ],
- [
- 1488468437.256,
- '10.171875',
- ],
- [
- 1488468497.256,
- '10.171875',
- ],
- [
- 1488468557.256,
- '10.171875',
- ],
- [
- 1488468617.256,
- '10.171875',
- ],
- [
- 1488468677.256,
- '10.17578125',
- ],
- [
- 1488468737.256,
- '10.17578125',
- ],
- [
- 1488468797.256,
- '10.265625',
- ],
- [
- 1488468857.256,
- '10.19921875',
- ],
- [
- 1488468917.256,
- '10.19921875',
- ],
- [
- 1488468977.256,
- '10.19921875',
- ],
- [
- 1488469037.256,
- '10.19921875',
- ],
- [
- 1488469097.256,
- '10.19921875',
- ],
- [
- 1488469157.256,
- '10.203125',
- ],
- [
- 1488469217.256,
- '10.43359375',
- ],
- [
- 1488469277.256,
- '10.20703125',
- ],
- [
- 1488469337.256,
- '10.2109375',
- ],
- [
- 1488469397.256,
- '10.22265625',
- ],
- [
- 1488469457.256,
- '10.21484375',
- ],
- [
- 1488469517.256,
- '10.21484375',
- ],
- [
- 1488469577.256,
- '10.21484375',
- ],
- [
- 1488469637.256,
- '10.22265625',
- ],
- [
- 1488469697.256,
- '10.234375',
- ],
- [
- 1488469757.256,
- '10.234375',
- ],
- [
- 1488469817.256,
- '10.234375',
- ],
- [
- 1488469877.256,
- '10.2421875',
- ],
- [
- 1488469937.256,
- '10.25',
- ],
- [
- 1488469997.256,
- '10.25390625',
- ],
- [
- 1488470057.256,
- '10.26171875',
- ],
- [
- 1488470117.256,
- '10.2734375',
- ],
- ],
- },
- ],
- memory_current: [
- {
- metric: {
- },
- value: [
- 1488470117.737,
- '10.2734375',
- ],
- },
- ],
- cpu_values: [
- {
- metric: {
- },
- values: [
- [
- 1488462918.15,
- '0.0002996458625058103',
- ],
- [
- 1488462978.15,
- '0.0002652382333333314',
- ],
- [
- 1488463038.15,
- '0.0003485461333333421',
- ],
- [
- 1488463098.15,
- '0.0003420421999999886',
- ],
- [
- 1488463158.15,
- '0.00023107150000001297',
- ],
- [
- 1488463218.15,
- '0.00030463981666664826',
- ],
- [
- 1488463278.15,
- '0.0002477177833333677',
- ],
- [
- 1488463338.15,
- '0.00026936656666665115',
- ],
- [
- 1488463398.15,
- '0.000406264750000022',
- ],
- [
- 1488463458.15,
- '0.00029592802026561453',
- ],
- [
- 1488463518.15,
- '0.00023426999683316343',
- ],
- [
- 1488463578.15,
- '0.0003057080666666915',
- ],
- [
- 1488463638.15,
- '0.0003408470500000149',
- ],
- [
- 1488463698.15,
- '0.00025497336666665166',
- ],
- [
- 1488463758.15,
- '0.0003009282833333534',
- ],
- [
- 1488463818.15,
- '0.0003119383499999924',
- ],
- [
- 1488463878.15,
- '0.00028719019999998705',
- ],
- [
- 1488463938.15,
- '0.000327864749999988',
- ],
- [
- 1488463998.15,
- '0.0002514917333333422',
- ],
- [
- 1488464058.15,
- '0.0003614651166666742',
- ],
- [
- 1488464118.15,
- '0.0003221668000000122',
- ],
- [
- 1488464178.15,
- '0.00023323083333330884',
- ],
- [
- 1488464238.15,
- '0.00028531499475009274',
- ],
- [
- 1488464298.15,
- '0.0002627695294921391',
- ],
- [
- 1488464358.15,
- '0.00027145463333333453',
- ],
- [
- 1488464418.15,
- '0.00025669488333335266',
- ],
- [
- 1488464478.15,
- '0.00022307761666665965',
- ],
- [
- 1488464538.15,
- '0.0003307265833333517',
- ],
- [
- 1488464598.15,
- '0.0002817050666666709',
- ],
- [
- 1488464658.15,
- '0.00022357458333332285',
- ],
- [
- 1488464718.15,
- '0.00032648590000000275',
- ],
- [
- 1488464778.15,
- '0.00028410750000000816',
- ],
- [
- 1488464838.15,
- '0.0003038076999999954',
- ],
- [
- 1488464898.15,
- '0.00037568226666667335',
- ],
- [
- 1488464958.15,
- '0.00020160354999999202',
- ],
- [
- 1488465018.15,
- '0.0003229403333333399',
- ],
- [
- 1488465078.15,
- '0.00033516069999999236',
- ],
- [
- 1488465138.15,
- '0.0003365978333333371',
- ],
- [
- 1488465198.15,
- '0.00020262178333331585',
- ],
- [
- 1488465258.15,
- '0.00040567498333331876',
- ],
- [
- 1488465318.15,
- '0.00029114155000001436',
- ],
- [
- 1488465378.15,
- '0.0002498841000000122',
- ],
- [
- 1488465438.15,
- '0.00027296763333331715',
- ],
- [
- 1488465498.15,
- '0.0002958794000000135',
- ],
- [
- 1488465558.15,
- '0.0002922354666666867',
- ],
- [
- 1488465618.15,
- '0.00034186624999999653',
- ],
- [
- 1488465678.15,
- '0.0003397984166666627',
- ],
- [
- 1488465738.15,
- '0.0002658284166666469',
- ],
- [
- 1488465798.15,
- '0.00026221139999999346',
- ],
- [
- 1488465858.15,
- '0.00029467960000001034',
- ],
- [
- 1488465918.15,
- '0.0002634141333333358',
- ],
- [
- 1488465978.15,
- '0.0003202958333333209',
- ],
- [
- 1488466038.15,
- '0.00037890760000000394',
- ],
- [
- 1488466098.15,
- '0.00023453356666666518',
- ],
- [
- 1488466158.15,
- '0.0002866827333333433',
- ],
- [
- 1488466218.15,
- '0.0003335935499999998',
- ],
- [
- 1488466278.15,
- '0.00022787131666666125',
- ],
- [
- 1488466338.15,
- '0.00033821938333333064',
- ],
- [
- 1488466398.15,
- '0.00029233375000001043',
- ],
- [
- 1488466458.15,
- '0.00026562758333333514',
- ],
- [
- 1488466518.15,
- '0.0003142600999999819',
- ],
- [
- 1488466578.15,
- '0.00027392178333333444',
- ],
- [
- 1488466638.15,
- '0.00028178598333334173',
- ],
- [
- 1488466698.15,
- '0.0002463400666666911',
- ],
- [
- 1488466758.15,
- '0.00040234373333332125',
- ],
- [
- 1488466818.15,
- '0.00023677453333332822',
- ],
- [
- 1488466878.15,
- '0.00030852703333333523',
- ],
- [
- 1488466938.15,
- '0.0003582272833333455',
- ],
- [
- 1488466998.15,
- '0.0002176380833332973',
- ],
- [
- 1488467058.15,
- '0.00026180203333335447',
- ],
- [
- 1488467118.15,
- '0.00027862966666667436',
- ],
- [
- 1488467178.15,
- '0.0002769731166666567',
- ],
- [
- 1488467238.15,
- '0.0002832899166666477',
- ],
- [
- 1488467298.15,
- '0.0003446533500000311',
- ],
- [
- 1488467358.15,
- '0.0002691345999999761',
- ],
- [
- 1488467418.15,
- '0.000284919933333357',
- ],
- [
- 1488467478.15,
- '0.0002396026166666528',
- ],
- [
- 1488467538.15,
- '0.00035625295000002075',
- ],
- [
- 1488467598.15,
- '0.00036759816666664946',
- ],
- [
- 1488467658.15,
- '0.00030326608333333855',
- ],
- [
- 1488467718.15,
- '0.00023584972418043393',
- ],
- [
- 1488467778.15,
- '0.00025744508892115107',
- ],
- [
- 1488467838.15,
- '0.00036737541666663395',
- ],
- [
- 1488467898.15,
- '0.00034325741666666094',
- ],
- [
- 1488467958.15,
- '0.00026390046666667407',
- ],
- [
- 1488468018.15,
- '0.0003302534500000102',
- ],
- [
- 1488468078.15,
- '0.00035243794999999527',
- ],
- [
- 1488468138.15,
- '0.00020149738333333407',
- ],
- [
- 1488468198.15,
- '0.0003183469666666679',
- ],
- [
- 1488468258.15,
- '0.0003835329166666845',
- ],
- [
- 1488468318.15,
- '0.0002485075333333124',
- ],
- [
- 1488468378.15,
- '0.0003011457166666768',
- ],
- [
- 1488468438.15,
- '0.00032242785497684965',
- ],
- [
- 1488468498.15,
- '0.0002659713747457531',
- ],
- [
- 1488468558.15,
- '0.0003476860333333202',
- ],
- [
- 1488468618.15,
- '0.00028336403333334794',
- ],
- [
- 1488468678.15,
- '0.00017132354999998728',
- ],
- [
- 1488468738.15,
- '0.0003001915833333276',
- ],
- [
- 1488468798.15,
- '0.0003025715666666725',
- ],
- [
- 1488468858.15,
- '0.0003012370166666815',
- ],
- [
- 1488468918.15,
- '0.00030203619999997025',
- ],
- [
- 1488468978.15,
- '0.0002804355000000314',
- ],
- [
- 1488469038.15,
- '0.00033194884999998564',
- ],
- [
- 1488469098.15,
- '0.00025201496666665455',
- ],
- [
- 1488469158.15,
- '0.0002777531500000189',
- ],
- [
- 1488469218.15,
- '0.0003314885833333392',
- ],
- [
- 1488469278.15,
- '0.0002234891422095589',
- ],
- [
- 1488469338.15,
- '0.000349117355867791',
- ],
- [
- 1488469398.15,
- '0.0004036731333333303',
- ],
- [
- 1488469458.15,
- '0.00024553911666667835',
- ],
- [
- 1488469518.15,
- '0.0003056456833333184',
- ],
- [
- 1488469578.15,
- '0.0002618737166666681',
- ],
- [
- 1488469638.15,
- '0.00022972643333331414',
- ],
- [
- 1488469698.15,
- '0.0003713522500000307',
- ],
- [
- 1488469758.15,
- '0.00018322576666666515',
- ],
- [
- 1488469818.15,
- '0.00034534762753952466',
- ],
- [
- 1488469878.15,
- '0.00028200510008501677',
- ],
- [
- 1488469938.15,
- '0.0002773708499999768',
- ],
- [
- 1488469998.15,
- '0.00027547160000001013',
- ],
- [
- 1488470058.15,
- '0.00031713610000000023',
- ],
- [
- 1488470118.15,
- '0.00035276853333332525',
- ],
- ],
- },
- ],
- cpu_current: [
- {
- metric: {
- },
- value: [
- 1488470118.566,
- '0.00035276853333332525',
- ],
- },
- ],
- last_update: '2017-03-02T15:55:18.981Z',
- },
- },
-};
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index 5ece4ed080b..2c096ed08a8 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -523,6 +523,51 @@ import '~/notes';
});
});
+ describe('postComment with Slash commands', () => {
+ const sampleComment = '/assign @root\n/award :100:';
+ const note = {
+ commands_changes: {
+ assignee_id: 1,
+ emoji_award: '100'
+ },
+ errors: {
+ commands_only: ['Commands applied']
+ },
+ valid: false
+ };
+ let $form;
+ let $notesContainer;
+
+ beforeEach(() => {
+ this.notes = new Notes('', []);
+ window.gon.current_username = 'root';
+ window.gon.current_user_fullname = 'Administrator';
+ gl.awardsHandler = {
+ addAwardToEmojiBar: () => {},
+ scrollToAwards: () => {}
+ };
+ gl.GfmAutoComplete = {
+ dataSources: {
+ commands: '/root/test-project/autocomplete_sources/commands'
+ }
+ };
+ $form = $('form.js-main-target-form');
+ $notesContainer = $('ul.main-notes-list');
+ $form.find('textarea.js-note-text').val(sampleComment);
+ });
+
+ it('should remove slash command placeholder when comment with slash commands is done posting', () => {
+ const deferred = $.Deferred();
+ spyOn($, 'ajax').and.returnValue(deferred.promise());
+ spyOn(gl.awardsHandler, 'addAwardToEmojiBar').and.callThrough();
+ $('.js-comment-button').click();
+
+ expect($notesContainer.find('.system-note.being-posted').length).toEqual(1); // Placeholder shown
+ deferred.resolve(note);
+ expect($notesContainer.find('.system-note.being-posted').length).toEqual(0); // Placeholder removed
+ });
+ });
+
describe('update comment with script tags', () => {
const sampleComment = '<script></script>';
const updatedComment = '<script></script>';
diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js
new file mode 100644
index 00000000000..f90e0093d25
--- /dev/null
+++ b/spec/javascripts/oauth_remember_me_spec.js
@@ -0,0 +1,26 @@
+import OAuthRememberMe from '~/oauth_remember_me';
+
+describe('OAuthRememberMe', () => {
+ preloadFixtures('static/oauth_remember_me.html.raw');
+
+ beforeEach(() => {
+ loadFixtures('static/oauth_remember_me.html.raw');
+
+ new OAuthRememberMe({ container: $('#oauth-container') }).bindEvents();
+ });
+
+ it('adds the "remember_me" query parameter to all OAuth login buttons', () => {
+ $('#oauth-container #remember_me').click();
+
+ expect($('#oauth-container .oauth-login.twitter').attr('href')).toBe('http://example.com/?remember_me=1');
+ expect($('#oauth-container .oauth-login.github').attr('href')).toBe('http://example.com/?remember_me=1');
+ });
+
+ it('removes the "remember_me" query parameter from all OAuth login buttons', () => {
+ $('#oauth-container #remember_me').click();
+ $('#oauth-container #remember_me').click();
+
+ expect($('#oauth-container .oauth-login.twitter').attr('href')).toBe('http://example.com/');
+ expect($('#oauth-container .oauth-login.github').attr('href')).toBe('http://example.com/');
+ });
+});
diff --git a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js b/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
index 56c57d94798..040d14efed2 100644
--- a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
+++ b/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
@@ -1,5 +1,8 @@
import Vue from 'vue';
-import IntervalPatternInput from '~/pipeline_schedules/components/interval_pattern_input';
+import Translate from '~/vue_shared/translate';
+import IntervalPatternInput from '~/pipeline_schedules/components/interval_pattern_input.vue';
+
+Vue.use(Translate);
const IntervalPatternInputComponent = Vue.extend(IntervalPatternInput);
const inputNameAttribute = 'schedule[cron]';
diff --git a/spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js b/spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
new file mode 100644
index 00000000000..5b316b319a5
--- /dev/null
+++ b/spec/javascripts/pipeline_schedules/setup_pipeline_variable_list_spec.js
@@ -0,0 +1,145 @@
+import {
+ setupPipelineVariableList,
+ insertRow,
+ removeRow,
+} from '~/pipeline_schedules/setup_pipeline_variable_list';
+
+describe('Pipeline Variable List', () => {
+ let $markup;
+
+ describe('insertRow', () => {
+ it('should insert another row', () => {
+ $markup = $(`<div>
+ <li class="js-row">
+ <input>
+ <textarea></textarea>
+ </li>
+ </div>`);
+
+ insertRow($markup.find('.js-row'));
+
+ expect($markup.find('.js-row').length).toBe(2);
+ });
+
+ it('should clear `data-is-persisted` on cloned row', () => {
+ $markup = $(`<div>
+ <li class="js-row" data-is-persisted="true"></li>
+ </div>`);
+
+ insertRow($markup.find('.js-row'));
+
+ const $lastRow = $markup.find('.js-row').last();
+ expect($lastRow.attr('data-is-persisted')).toBe(undefined);
+ });
+
+ it('should clear inputs on cloned row', () => {
+ $markup = $(`<div>
+ <li class="js-row">
+ <input value="foo">
+ <textarea>bar</textarea>
+ </li>
+ </div>`);
+
+ insertRow($markup.find('.js-row'));
+
+ const $lastRow = $markup.find('.js-row').last();
+ expect($lastRow.find('input').val()).toBe('');
+ expect($lastRow.find('textarea').val()).toBe('');
+ });
+ });
+
+ describe('removeRow', () => {
+ it('should remove dynamic row', () => {
+ $markup = $(`<div>
+ <li class="js-row">
+ <input>
+ <textarea></textarea>
+ </li>
+ </div>`);
+
+ removeRow($markup.find('.js-row'));
+
+ expect($markup.find('.js-row').length).toBe(0);
+ });
+
+ it('should hide and mark to destroy with already persisted rows', () => {
+ $markup = $(`<div>
+ <li class="js-row" data-is-persisted="true">
+ <input class="js-destroy-input">
+ </li>
+ </div>`);
+
+ const $row = $markup.find('.js-row');
+ removeRow($row);
+
+ expect($row.find('.js-destroy-input').val()).toBe('1');
+ expect($markup.find('.js-row').length).toBe(1);
+ });
+ });
+
+ describe('setupPipelineVariableList', () => {
+ beforeEach(() => {
+ $markup = $(`<form>
+ <li class="js-row">
+ <input class="js-user-input" name="schedule[variables_attributes][][key]">
+ <textarea class="js-user-input" name="schedule[variables_attributes][][value]"></textarea>
+ <button class="js-row-remove-button"></button>
+ <button class="js-row-add-button"></button>
+ </li>
+ </form>`);
+
+ setupPipelineVariableList($markup);
+ });
+
+ it('should remove the row when clicking the remove button', () => {
+ $markup.find('.js-row-remove-button').trigger('click');
+
+ expect($markup.find('.js-row').length).toBe(0);
+ });
+
+ it('should add another row when editing the last rows key input', () => {
+ const $row = $markup.find('.js-row');
+ $row.find('input.js-user-input')
+ .val('foo')
+ .trigger('input');
+
+ expect($markup.find('.js-row').length).toBe(2);
+ });
+
+ it('should add another row when editing the last rows value textarea', () => {
+ const $row = $markup.find('.js-row');
+ $row.find('textarea.js-user-input')
+ .val('foo')
+ .trigger('input');
+
+ expect($markup.find('.js-row').length).toBe(2);
+ });
+
+ it('should remove empty row after blurring', () => {
+ const $row = $markup.find('.js-row');
+ $row.find('input.js-user-input')
+ .val('foo')
+ .trigger('input');
+
+ expect($markup.find('.js-row').length).toBe(2);
+
+ $row.find('input.js-user-input')
+ .val('')
+ .trigger('input')
+ .trigger('blur');
+
+ expect($markup.find('.js-row').length).toBe(1);
+ });
+
+ it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => {
+ const $row = $markup.find('.js-row');
+ expect($row.find('input').attr('name')).toBe('schedule[variables_attributes][][key]');
+ expect($row.find('textarea').attr('name')).toBe('schedule[variables_attributes][][value]');
+
+ $markup.filter('form').submit();
+
+ expect($row.find('input').attr('name')).toBe('');
+ expect($row.find('textarea').attr('name')).toBe('');
+ });
+ });
+});
diff --git a/spec/javascripts/pipelines/stage_spec.js b/spec/javascripts/pipelines/stage_spec.js
index a4f32a1faed..1b96b2e3d51 100644
--- a/spec/javascripts/pipelines/stage_spec.js
+++ b/spec/javascripts/pipelines/stage_spec.js
@@ -83,4 +83,47 @@ describe('Pipelines stage component', () => {
}, 0);
});
});
+
+ describe('update endpoint correctly', () => {
+ const updatedInterceptor = (request, next) => {
+ if (request.url === 'bar') {
+ next(request.respondWith(JSON.stringify({ html: 'this is the updated content' }), {
+ status: 200,
+ }));
+ }
+ next();
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(updatedInterceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(
+ Vue.http.interceptors, updatedInterceptor,
+ );
+ });
+
+ it('should update the stage to request the new endpoint provided', (done) => {
+ component.stage = {
+ status: {
+ group: 'running',
+ icon: 'running',
+ title: 'running',
+ },
+ dropdown_path: 'bar',
+ };
+
+ Vue.nextTick(() => {
+ component.$el.querySelector('button').click();
+
+ setTimeout(() => {
+ expect(
+ component.$el.querySelector('.js-builds-dropdown-container ul').textContent.trim(),
+ ).toEqual('this is the updated content');
+ done();
+ });
+ });
+ });
+ });
});
diff --git a/spec/javascripts/prometheus_metrics/mock_data.js b/spec/javascripts/prometheus_metrics/mock_data.js
new file mode 100644
index 00000000000..3af56df92e2
--- /dev/null
+++ b/spec/javascripts/prometheus_metrics/mock_data.js
@@ -0,0 +1,41 @@
+export const metrics = [
+ {
+ group: 'Kubernetes',
+ priority: 1,
+ active_metrics: 4,
+ metrics_missing_requirements: 0,
+ },
+ {
+ group: 'HAProxy',
+ priority: 2,
+ active_metrics: 3,
+ metrics_missing_requirements: 0,
+ },
+ {
+ group: 'Apache',
+ priority: 3,
+ active_metrics: 5,
+ metrics_missing_requirements: 0,
+ },
+];
+
+export const missingVarMetrics = [
+ {
+ group: 'Kubernetes',
+ priority: 1,
+ active_metrics: 4,
+ metrics_missing_requirements: 0,
+ },
+ {
+ group: 'HAProxy',
+ priority: 2,
+ active_metrics: 3,
+ metrics_missing_requirements: 1,
+ },
+ {
+ group: 'Apache',
+ priority: 3,
+ active_metrics: 5,
+ metrics_missing_requirements: 3,
+ },
+];
diff --git a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
new file mode 100644
index 00000000000..2b3a821dbd9
--- /dev/null
+++ b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js
@@ -0,0 +1,158 @@
+import PrometheusMetrics from '~/prometheus_metrics/prometheus_metrics';
+import PANEL_STATE from '~/prometheus_metrics/constants';
+import { metrics, missingVarMetrics } from './mock_data';
+
+describe('PrometheusMetrics', () => {
+ const FIXTURE = 'services/prometheus/prometheus_service.html.raw';
+ preloadFixtures(FIXTURE);
+
+ beforeEach(() => {
+ loadFixtures(FIXTURE);
+ });
+
+ describe('constructor', () => {
+ let prometheusMetrics;
+
+ beforeEach(() => {
+ prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
+ });
+
+ it('should initialize wrapper element refs on class object', () => {
+ expect(prometheusMetrics.$wrapper).toBeDefined();
+ expect(prometheusMetrics.$monitoredMetricsPanel).toBeDefined();
+ expect(prometheusMetrics.$monitoredMetricsCount).toBeDefined();
+ expect(prometheusMetrics.$monitoredMetricsLoading).toBeDefined();
+ expect(prometheusMetrics.$monitoredMetricsEmpty).toBeDefined();
+ expect(prometheusMetrics.$monitoredMetricsList).toBeDefined();
+ expect(prometheusMetrics.$missingEnvVarPanel).toBeDefined();
+ expect(prometheusMetrics.$panelToggle).toBeDefined();
+ expect(prometheusMetrics.$missingEnvVarMetricCount).toBeDefined();
+ expect(prometheusMetrics.$missingEnvVarMetricsList).toBeDefined();
+ });
+
+ it('should initialize metadata on class object', () => {
+ expect(prometheusMetrics.backOffRequestCounter).toEqual(0);
+ expect(prometheusMetrics.activeMetricsEndpoint).toContain('/test');
+ });
+ });
+
+ describe('showMonitoringMetricsPanelState', () => {
+ let prometheusMetrics;
+
+ beforeEach(() => {
+ prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
+ });
+
+ it('should show loading state when called with `loading`', () => {
+ prometheusMetrics.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
+
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeTruthy();
+ });
+
+ it('should show metrics list when called with `list`', () => {
+ prometheusMetrics.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
+
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeFalsy();
+ });
+
+ it('should show empty state when called with `empty`', () => {
+ prometheusMetrics.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
+
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeFalsy();
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeTruthy();
+ });
+ });
+
+ describe('populateActiveMetrics', () => {
+ let prometheusMetrics;
+
+ beforeEach(() => {
+ prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
+ });
+
+ it('should show monitored metrics list', () => {
+ prometheusMetrics.populateActiveMetrics(metrics);
+
+ const $metricsListLi = prometheusMetrics.$monitoredMetricsList.find('li');
+
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsList.hasClass('hidden')).toBeFalsy();
+
+ expect(prometheusMetrics.$monitoredMetricsCount.text()).toEqual('12');
+ expect($metricsListLi.length).toEqual(metrics.length);
+ expect($metricsListLi.first().find('.badge').text()).toEqual(`${metrics[0].active_metrics}`);
+ });
+
+ it('should show missing environment variables list', () => {
+ prometheusMetrics.populateActiveMetrics(missingVarMetrics);
+
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$missingEnvVarPanel.hasClass('hidden')).toBeFalsy();
+
+ expect(prometheusMetrics.$missingEnvVarMetricCount.text()).toEqual('2');
+ expect(prometheusMetrics.$missingEnvVarPanel.find('li').length).toEqual(2);
+ expect(prometheusMetrics.$missingEnvVarPanel.find('.flash-container')).toBeDefined();
+ });
+ });
+
+ describe('loadActiveMetrics', () => {
+ let prometheusMetrics;
+
+ beforeEach(() => {
+ prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
+ });
+
+ it('should show loader animation while response is being loaded and hide it when request is complete', (done) => {
+ const deferred = $.Deferred();
+ spyOn($, 'getJSON').and.returnValue(deferred.promise());
+
+ prometheusMetrics.loadActiveMetrics();
+
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeFalsy();
+ expect($.getJSON).toHaveBeenCalledWith(prometheusMetrics.activeMetricsEndpoint);
+
+ deferred.resolve({ data: metrics, success: true });
+
+ setTimeout(() => {
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ done();
+ });
+ });
+
+ it('should show empty state if response failed to load', (done) => {
+ const deferred = $.Deferred();
+ spyOn($, 'getJSON').and.returnValue(deferred.promise());
+ spyOn(prometheusMetrics, 'populateActiveMetrics');
+
+ prometheusMetrics.loadActiveMetrics();
+
+ deferred.reject();
+
+ setTimeout(() => {
+ expect(prometheusMetrics.$monitoredMetricsLoading.hasClass('hidden')).toBeTruthy();
+ expect(prometheusMetrics.$monitoredMetricsEmpty.hasClass('hidden')).toBeFalsy();
+ done();
+ });
+ });
+
+ it('should populate metrics list once response is loaded', (done) => {
+ const deferred = $.Deferred();
+ spyOn($, 'getJSON').and.returnValue(deferred.promise());
+ spyOn(prometheusMetrics, 'populateActiveMetrics');
+
+ prometheusMetrics.loadActiveMetrics();
+
+ deferred.resolve({ data: metrics, success: true });
+
+ setTimeout(() => {
+ expect(prometheusMetrics.populateActiveMetrics).toHaveBeenCalledWith(metrics);
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/sidebar/assignee_title_spec.js b/spec/javascripts/sidebar/assignee_title_spec.js
index 5b5b1bf4140..ac93f918ce4 100644
--- a/spec/javascripts/sidebar/assignee_title_spec.js
+++ b/spec/javascripts/sidebar/assignee_title_spec.js
@@ -33,6 +33,31 @@ describe('AssigneeTitle component', () => {
});
});
+ describe('gutter toggle', () => {
+ it('does not show toggle by default', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 2,
+ editable: false,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.gutter-toggle')).toBeNull();
+ });
+
+ it('shows toggle when showToggle is true', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 2,
+ editable: false,
+ showToggle: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.gutter-toggle')).toEqual(jasmine.any(Object));
+ });
+ });
+
it('does not render spinner by default', () => {
component = new AssigneeTitleComponent({
propsData: {
diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js
index 0a32797c3e2..a53e8a94d89 100644
--- a/spec/javascripts/signin_tabs_memoizer_spec.js
+++ b/spec/javascripts/signin_tabs_memoizer_spec.js
@@ -1,8 +1,7 @@
import AccessorUtilities from '~/lib/utils/accessor';
+import SigninTabsMemoizer from '~/signin_tabs_memoizer';
-import '~/signin_tabs_memoizer';
-
-((global) => {
+(() => {
describe('SigninTabsMemoizer', () => {
const fixtureTemplate = 'static/signin_tabs.html.raw';
const tabSelector = 'ul.nav-tabs';
@@ -10,7 +9,7 @@ import '~/signin_tabs_memoizer';
let memo;
function createMemoizer() {
- memo = new global.ActiveTabMemoizer({
+ memo = new SigninTabsMemoizer({
currentTabKey,
tabSelector,
});
@@ -78,7 +77,7 @@ import '~/signin_tabs_memoizer';
beforeEach(function () {
memo.isLocalStorageAvailable = false;
- global.ActiveTabMemoizer.prototype.saveData.call(memo);
+ SigninTabsMemoizer.prototype.saveData.call(memo);
});
it('should not call .setItem', () => {
@@ -92,7 +91,7 @@ import '~/signin_tabs_memoizer';
beforeEach(function () {
memo.isLocalStorageAvailable = true;
- global.ActiveTabMemoizer.prototype.saveData.call(memo, value);
+ SigninTabsMemoizer.prototype.saveData.call(memo, value);
});
it('should call .setItem', () => {
@@ -117,7 +116,7 @@ import '~/signin_tabs_memoizer';
beforeEach(function () {
memo.isLocalStorageAvailable = false;
- readData = global.ActiveTabMemoizer.prototype.readData.call(memo);
+ readData = SigninTabsMemoizer.prototype.readData.call(memo);
});
it('should not call .getItem and should return `null`', () => {
@@ -130,7 +129,7 @@ import '~/signin_tabs_memoizer';
beforeEach(function () {
memo.isLocalStorageAvailable = true;
- readData = global.ActiveTabMemoizer.prototype.readData.call(memo);
+ readData = SigninTabsMemoizer.prototype.readData.call(memo);
});
it('should call .getItem and return the localStorage value', () => {
@@ -140,4 +139,4 @@ import '~/signin_tabs_memoizer';
});
});
});
-})(window);
+})();
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index f0d51bd0902..d4e134583c7 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -7,6 +7,10 @@ import '~/commons';
import Vue from 'vue';
import VueResource from 'vue-resource';
+const isHeadlessChrome = /\bHeadlessChrome\//.test(navigator.userAgent);
+Vue.config.devtools = !isHeadlessChrome;
+Vue.config.productionTip = false;
+
Vue.use(VueResource);
// enable test fixtures
@@ -22,6 +26,19 @@ window.gl = window.gl || {};
window.gl.TEST_HOST = 'http://test.host';
window.gon = window.gon || {};
+let hasUnhandledPromiseRejections = false;
+
+window.addEventListener('unhandledrejection', (event) => {
+ hasUnhandledPromiseRejections = true;
+ console.error('Unhandled promise rejection:');
+ console.error(event.reason.stack || event.reason);
+});
+
+const checkUnhandledPromiseRejections = (done) => {
+ expect(hasUnhandledPromiseRejections).toBe(false);
+ done();
+};
+
// HACK: Chrome 59 disconnects if there are too many synchronous tests in a row
// because it appears to lock up the thread that communicates to Karma's socket
// This async beforeEach gets called on every spec and releases the JS thread long
@@ -63,6 +80,10 @@ testsContext.keys().forEach(function (path) {
}
});
+it('has no unhandled Promise rejections', (done) => {
+ setTimeout(checkUnhandledPromiseRejections(done), 1000);
+});
+
// if we're generating coverage reports, make sure to include all files so
// that we can catch files with 0% coverage
// see: https://github.com/deepsweet/istanbul-instrumenter-loader/issues/15
diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js
index cd74aba4a4e..fd492159081 100644
--- a/spec/javascripts/todos_spec.js
+++ b/spec/javascripts/todos_spec.js
@@ -1,4 +1,4 @@
-import '~/todos';
+import Todos from '~/todos';
import '~/lib/utils/common_utils';
describe('Todos', () => {
@@ -9,7 +9,7 @@ describe('Todos', () => {
loadFixtures('todos/todos.html.raw');
todoItem = document.querySelector('.todos-list .todo');
- return new gl.Todos();
+ return new Todos();
});
describe('goToTodoUrl', () => {
diff --git a/spec/javascripts/visibility_select_spec.js b/spec/javascripts/visibility_select_spec.js
index c2eaea7c2ed..82714cb69bd 100644
--- a/spec/javascripts/visibility_select_spec.js
+++ b/spec/javascripts/visibility_select_spec.js
@@ -1,8 +1,6 @@
-import '~/visibility_select';
+import VisibilitySelect from '~/visibility_select';
(() => {
- const VisibilitySelect = gl.VisibilitySelect;
-
describe('VisibilitySelect', function () {
const lockedElement = document.createElement('div');
lockedElement.dataset.helpBlock = 'lockedHelpBlock';
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js
index d4b200875df..ab8a3f6c64c 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js
@@ -10,6 +10,7 @@ const deploymentMockData = [
url: '/root/acets-review-apps/environments/15',
stop_url: '/root/acets-review-apps/environments/15/stop',
metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
+ metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
external_url: 'http://diplo.',
external_url_formatted: 'diplo.',
deployed_at: '2017-03-22T22:44:42.258Z',
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
index 7f3eea7d2e5..06f89fabf42 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
@@ -54,6 +54,7 @@ describe('MRWidgetHeader', () => {
sourceBranch: 'mr-widget-refactor',
sourceBranchLink: `<a href="${sourceBranchPath}">mr-widget-refactor</a>`,
targetBranchPath: 'foo/bar/commits-path',
+ targetBranchTreePath: 'foo/bar/tree/path',
targetBranch: 'master',
isOpen: true,
emailPatchesPath: '/mr/email-patches',
@@ -69,12 +70,14 @@ describe('MRWidgetHeader', () => {
expect(el.classList.contains('mr-source-target')).toBeTruthy();
const sourceBranchLink = el.querySelectorAll('.label-branch')[0];
const targetBranchLink = el.querySelectorAll('.label-branch')[1];
+ const commitsCount = el.querySelector('.diverged-commits-count');
expect(sourceBranchLink.textContent).toContain(mr.sourceBranch);
expect(targetBranchLink.textContent).toContain(mr.targetBranch);
expect(sourceBranchLink.querySelector('a').getAttribute('href')).toEqual(sourceBranchPath);
- expect(targetBranchLink.querySelector('a').getAttribute('href')).toEqual(mr.targetBranchPath);
- expect(el.querySelector('.diverged-commits-count').textContent).toContain('12 commits behind');
+ expect(targetBranchLink.querySelector('a').getAttribute('href')).toEqual(mr.targetBranchTreePath);
+ expect(commitsCount.textContent).toContain('12 commits behind');
+ expect(commitsCount.querySelector('a').getAttribute('href')).toEqual(mr.targetBranchPath);
expect(el.textContent).toContain('Check out branch');
expect(el.querySelectorAll('.dropdown li a')[0].getAttribute('href')).toEqual(mr.emailPatchesPath);
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
index 2c3d0ddff28..6adcbc73ed7 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js
@@ -3,6 +3,7 @@ import memoryUsageComponent from '~/vue_merge_request_widget/components/mr_widge
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
const url = '/root/acets-review-apps/environments/15/deployments/1/metrics';
+const monitoringUrl = '/root/acets-review-apps/environments/15/metrics';
const metricsMockData = {
success: true,
@@ -39,6 +40,7 @@ const createComponent = () => {
el: document.createElement('div'),
propsData: {
metricsUrl: url,
+ metricsMonitoringUrl: monitoringUrl,
memoryMetrics: [],
deploymentTime: 0,
hasMetrics: false,
diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js
index 1c3188cdda2..d5754aaa9e7 100644
--- a/spec/javascripts/vue_shared/components/commit_spec.js
+++ b/spec/javascripts/vue_shared/components/commit_spec.js
@@ -22,7 +22,7 @@ describe('Commit component', () => {
shortSha: 'b7836edd',
title: 'Commit message',
author: {
- avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png',
+ avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png',
web_url: 'https://gitlab.com/jschatz1',
path: '/jschatz1',
username: 'jschatz1',
@@ -45,7 +45,7 @@ describe('Commit component', () => {
shortSha: 'b7836edd',
title: 'Commit message',
author: {
- avatar_url: 'https://gitlab.com/uploads/system/user/avatar/300478/avatar.png',
+ avatar_url: 'https://gitlab.com/uploads/-/system/user/avatar/300478/avatar.png',
web_url: 'https://gitlab.com/jschatz1',
path: '/jschatz1',
username: 'jschatz1',
diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js
index 4bbaff561fc..291e19c9f3c 100644
--- a/spec/javascripts/vue_shared/components/markdown/field_spec.js
+++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js
@@ -4,47 +4,33 @@ import fieldComponent from '~/vue_shared/components/markdown/field.vue';
describe('Markdown field component', () => {
let vm;
- beforeEach(() => {
+ beforeEach((done) => {
vm = new Vue({
- render(createElement) {
- return createElement(
- fieldComponent,
- {
- props: {
- markdownPreviewUrl: '/preview',
- markdownDocs: '/docs',
- },
- },
- [
- createElement('textarea', {
- slot: 'textarea',
- }),
- ],
- );
+ data() {
+ return {
+ text: 'testing\n123',
+ };
},
- });
- });
-
- it('creates a new instance of GL form', (done) => {
- spyOn(gl, 'GLForm');
- vm.$mount();
-
- Vue.nextTick(() => {
- expect(
- gl.GLForm,
- ).toHaveBeenCalled();
-
- done();
- });
+ components: {
+ fieldComponent,
+ },
+ template: `
+ <field-component
+ marodown-preview-url="/preview"
+ markdown-docs="/docs"
+ >
+ <textarea
+ slot="textarea"
+ v-model="text">
+ </textarea>
+ </field-component>
+ `,
+ }).$mount();
+
+ Vue.nextTick(done);
});
describe('mounted', () => {
- beforeEach((done) => {
- vm.$mount();
-
- Vue.nextTick(done);
- });
-
it('renders textarea inside backdrop', () => {
expect(
vm.$el.querySelector('.zen-backdrop textarea'),
@@ -117,5 +103,52 @@ describe('Markdown field component', () => {
});
});
});
+
+ describe('markdown buttons', () => {
+ it('converts single words', (done) => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.setSelectionRange(0, 7);
+ vm.$el.querySelector('.js-md').click();
+
+ Vue.nextTick(() => {
+ expect(
+ textarea.value,
+ ).toContain('**testing**');
+
+ done();
+ });
+ });
+
+ it('converts a line', (done) => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.setSelectionRange(0, 0);
+ vm.$el.querySelectorAll('.js-md')[4].click();
+
+ Vue.nextTick(() => {
+ expect(
+ textarea.value,
+ ).toContain('* testing');
+
+ done();
+ });
+ });
+
+ it('converts multiple lines', (done) => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.setSelectionRange(0, 50);
+ vm.$el.querySelectorAll('.js-md')[4].click();
+
+ Vue.nextTick(() => {
+ expect(
+ textarea.value,
+ ).toContain('* testing\n* 123');
+
+ done();
+ });
+ });
+ });
});
});
diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js b/spec/javascripts/vue_shared/components/table_pagination_spec.js
index 895e1c585b4..b0b78e34e0f 100644
--- a/spec/javascripts/vue_shared/components/table_pagination_spec.js
+++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js
@@ -1,150 +1,188 @@
import Vue from 'vue';
import paginationComp from '~/vue_shared/components/table_pagination.vue';
-import '~/lib/utils/common_utils';
describe('Pagination component', () => {
let component;
let PaginationComponent;
-
- const changeChanges = {
- one: '',
- };
-
- const change = (one) => {
- changeChanges.one = one;
- };
+ let spy;
+ let mountComponet;
beforeEach(() => {
+ spy = jasmine.createSpy('spy');
PaginationComponent = Vue.extend(paginationComp);
- });
-
- it('should render and start at page 1', () => {
- component = new PaginationComponent({
- propsData: {
- pageInfo: {
- totalPages: 10,
- nextPage: 2,
- previousPage: '',
- },
- change,
- },
- }).$mount();
- expect(component.$el.classList).toContain('gl-pagination');
-
- component.changePage({ target: { innerText: '1' } });
-
- expect(changeChanges.one).toEqual(1);
+ mountComponet = function (props) {
+ return new PaginationComponent({
+ propsData: props,
+ }).$mount();
+ };
});
- it('should go to the previous page', () => {
- component = new PaginationComponent({
- propsData: {
+ describe('render', () => {
+ describe('prev button', () => {
+ it('should be disabled and non clickable', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 2,
+ page: 1,
+ perPage: 20,
+ previousPage: NaN,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ expect(
+ component.$el.querySelector('.js-previous-button').classList.contains('disabled'),
+ ).toEqual(true);
+
+ component.$el.querySelector('.js-previous-button a').click();
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('should be enabled and clickable', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 3,
+ page: 2,
+ perPage: 20,
+ previousPage: 1,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ component.$el.querySelector('.js-previous-button a').click();
+
+ expect(spy).toHaveBeenCalledWith(1);
+ });
+ });
+
+ describe('first button', () => {
+ it('should call the change callback with the first page', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 3,
+ page: 2,
+ perPage: 20,
+ previousPage: 1,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ const button = component.$el.querySelector('.js-first-button a');
+
+ expect(button.textContent.trim()).toEqual('« First');
+
+ button.click();
+
+ expect(spy).toHaveBeenCalledWith(1);
+ });
+ });
+
+ describe('last button', () => {
+ it('should call the change callback with the last page', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 3,
+ page: 2,
+ perPage: 20,
+ previousPage: 1,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ const button = component.$el.querySelector('.js-last-button a');
+
+ expect(button.textContent.trim()).toEqual('Last »');
+
+ button.click();
+
+ expect(spy).toHaveBeenCalledWith(5);
+ });
+ });
+
+ describe('next button', () => {
+ it('should be disabled and non clickable', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 5,
+ page: 5,
+ perPage: 20,
+ previousPage: 1,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ expect(
+ component.$el.querySelector('.js-next-button').textContent.trim(),
+ ).toEqual('Next');
+
+ component.$el.querySelector('.js-next-button a').click();
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('should be enabled and clickable', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 4,
+ page: 3,
+ perPage: 20,
+ previousPage: 2,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ component.$el.querySelector('.js-next-button a').click();
+
+ expect(spy).toHaveBeenCalledWith(4);
+ });
+ });
+
+ describe('numbered buttons', () => {
+ it('should render 5 pages', () => {
+ component = mountComponet({
+ pageInfo: {
+ nextPage: 4,
+ page: 3,
+ perPage: 20,
+ previousPage: 2,
+ total: 84,
+ totalPages: 5,
+ },
+ change: spy,
+ });
+
+ expect(component.$el.querySelectorAll('.page').length).toEqual(5);
+ });
+ });
+
+ it('should render the spread operator', () => {
+ component = mountComponet({
pageInfo: {
+ nextPage: 4,
+ page: 3,
+ perPage: 20,
+ previousPage: 2,
+ total: 84,
totalPages: 10,
- nextPage: 3,
- previousPage: 1,
},
- change,
- },
- }).$mount();
-
- component.changePage({ target: { innerText: 'Prev' } });
-
- expect(changeChanges.one).toEqual(1);
- });
-
- it('should go to the next page', () => {
- component = new PaginationComponent({
- propsData: {
- pageInfo: {
- totalPages: 10,
- nextPage: 5,
- previousPage: 3,
- },
- change,
- },
- }).$mount();
-
- component.changePage({ target: { innerText: 'Next' } });
-
- expect(changeChanges.one).toEqual(5);
- });
-
- it('should go to the last page', () => {
- component = new PaginationComponent({
- propsData: {
- pageInfo: {
- totalPages: 10,
- nextPage: 5,
- previousPage: 3,
- },
- change,
- },
- }).$mount();
-
- component.changePage({ target: { innerText: 'Last »' } });
-
- expect(changeChanges.one).toEqual(10);
- });
-
- it('should go to the first page', () => {
- component = new PaginationComponent({
- propsData: {
- pageInfo: {
- totalPages: 10,
- nextPage: 5,
- previousPage: 3,
- },
- change,
- },
- }).$mount();
-
- component.changePage({ target: { innerText: '« First' } });
-
- expect(changeChanges.one).toEqual(1);
- });
-
- it('should do nothing', () => {
- component = new PaginationComponent({
- propsData: {
- pageInfo: {
- totalPages: 10,
- nextPage: 2,
- previousPage: '',
- },
- change,
- },
- }).$mount();
-
- component.changePage({ target: { innerText: '...' } });
-
- expect(changeChanges.one).toEqual(1);
- });
-});
-
-describe('paramHelper', () => {
- afterEach(() => {
- window.history.pushState({}, null, '');
- });
-
- it('can parse url parameters correctly', () => {
- window.history.pushState({}, null, '?scope=all&p=2');
-
- const scope = gl.utils.getParameterByName('scope');
- const p = gl.utils.getParameterByName('p');
-
- expect(scope).toEqual('all');
- expect(p).toEqual('2');
- });
-
- it('returns null if param not in url', () => {
- window.history.pushState({}, null, '?p=2');
-
- const scope = gl.utils.getParameterByName('scope');
- const p = gl.utils.getParameterByName('p');
+ change: spy,
+ });
- expect(scope).toEqual(null);
- expect(p).toEqual('2');
+ expect(component.$el.querySelector('.separator').textContent.trim()).toEqual('...');
+ });
});
});
diff --git a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js b/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
index f3b4adc0b70..b4c1f70ed1e 100644
--- a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
+++ b/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js
@@ -22,7 +22,6 @@ describe('Time ago with tooltip component', () => {
}).$mount();
expect(vm.$el.tagName).toEqual('TIME');
- expect(vm.$el.classList.contains('js-vue-timeago')).toEqual(true);
expect(
vm.$el.getAttribute('data-original-title'),
).toEqual(gl.utils.formatDate('2017-05-08T14:57:39.781Z'));
diff --git a/spec/javascripts/vue_shared/directives/tooltip_spec.js b/spec/javascripts/vue_shared/directives/tooltip_spec.js
new file mode 100644
index 00000000000..b1b3071527b
--- /dev/null
+++ b/spec/javascripts/vue_shared/directives/tooltip_spec.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import tooltip from '~/vue_shared/directives/tooltip';
+
+describe('Tooltip directive', () => {
+ let vm;
+
+ afterEach(() => {
+ if (vm) {
+ vm.$destroy();
+ }
+ });
+
+ describe('with a single tooltip', () => {
+ beforeEach(() => {
+ const SomeComponent = Vue.extend({
+ directives: {
+ tooltip,
+ },
+ template: `
+ <div
+ v-tooltip
+ title="foo">
+ </div>
+ `,
+ });
+
+ vm = new SomeComponent().$mount();
+ });
+
+ it('should have tooltip plugin applied', () => {
+ expect($(vm.$el).data('bs.tooltip')).toBeDefined();
+ });
+ });
+
+ describe('with multiple tooltips', () => {
+ beforeEach(() => {
+ const SomeComponent = Vue.extend({
+ directives: {
+ tooltip,
+ },
+ template: `
+ <div>
+ <div
+ v-tooltip
+ class="js-look-for-tooltip"
+ title="foo">
+ </div>
+ <div
+ v-tooltip
+ title="bar">
+ </div>
+ </div>
+ `,
+ });
+
+ vm = new SomeComponent().$mount();
+ });
+
+ it('should have tooltip plugin applied to all instances', () => {
+ expect($(vm.$el).find('.js-look-for-tooltip').data('bs.tooltip')).toBeDefined();
+ });
+ });
+});
diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js
index 4399c8b2025..a225b04c47e 100644
--- a/spec/javascripts/zen_mode_spec.js
+++ b/spec/javascripts/zen_mode_spec.js
@@ -1,9 +1,8 @@
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-return-assign, new-cap, max-len */
/* global Dropzone */
/* global Mousetrap */
-/* global ZenMode */
-import '~/zen_mode';
+import ZenMode from '~/zen_mode';
(function() {
var enterZen, escapeKeydown, exitZen;
diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
index 787212581e2..d70749536b8 100644
--- a/spec/lib/banzai/cross_project_reference_spec.rb
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::CrossProjectReference, lib: true do
+describe Banzai::CrossProjectReference do
include described_class
describe '#project_from_ref' do
diff --git a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb
index 33b812ef425..34f1657b6d3 100644
--- a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb
+++ b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::AsciiDocPostProcessingFilter, lib: true do
+describe Banzai::Filter::AsciiDocPostProcessingFilter do
include FilterSpecHelper
it "adds class for elements with data-math-style" do
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index a6d2ea11fcc..b7c2ff03125 100644
--- a/spec/lib/banzai/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::AutolinkFilter, lib: true do
+describe Banzai::Filter::AutolinkFilter do
include FilterSpecHelper
let(:link) { 'http://about.gitlab.com/' }
diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
index 2799249ae3e..8224dc5a6b9 100644
--- a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
+++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Banzai::Filter::BlockquoteFenceFilter, lib: true do
+describe Banzai::Filter::BlockquoteFenceFilter do
include FilterSpecHelper
it 'converts blockquote fences to blockquote lines' do
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index fc67c7ec3c4..11d48387544 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
+describe Banzai::Filter::CommitRangeReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public, :repository) }
@@ -29,14 +29,14 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
doc = reference_filter("See #{reference2}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_compare_url(project.namespace, project, range2.to_param)
+ .to eq urls.project_compare_url(project, range2.to_param)
end
it 'links to a valid three-dot reference' do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_compare_url(project.namespace, project, range.to_param)
+ .to eq urls.project_compare_url(project, range.to_param)
end
it 'links to a valid short ID' do
@@ -94,7 +94,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
link = doc.css('a').first.attr('href')
expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_compare_url(project.namespace, project, from: commit1.id, to: commit2.id, only_path: true)
+ expect(link).to eq urls.project_compare_url(project, from: commit1.id, to: commit2.id, only_path: true)
end
end
@@ -106,7 +106,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ .to eq urls.project_compare_url(project2, range.to_param)
end
it 'link has valid text' do
@@ -141,7 +141,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ .to eq urls.project_compare_url(project2, range.to_param)
end
it 'link has valid text' do
@@ -176,7 +176,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ .to eq urls.project_compare_url(project2, range.to_param)
end
it 'link has valid text' do
@@ -205,7 +205,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
let(:namespace) { create(:namespace) }
let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:range) { CommitRange.new("#{commit1.id}...master", project) }
- let(:reference) { urls.namespace_project_compare_url(project2.namespace, project2, from: commit1.id, to: 'master') }
+ let(:reference) { urls.project_compare_url(project2, from: commit1.id, to: 'master') }
before do
range.project = project2
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index c4d8d3b6682..fb2a36d1ba1 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::CommitReferenceFilter, lib: true do
+describe Banzai::Filter::CommitReferenceFilter do
include FilterSpecHelper
let(:project) { create(:project, :public, :repository) }
@@ -27,7 +27,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
expect(doc.css('a').first.text).to eq commit.short_id
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_commit_url(project.namespace, project, reference)
+ .to eq urls.project_commit_url(project, reference)
end
end
@@ -90,7 +90,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
link = doc.css('a').first.attr('href')
expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_commit_url(project.namespace, project, reference, only_path: true)
+ expect(link).to eq urls.project_commit_url(project, reference, only_path: true)
end
end
@@ -175,13 +175,13 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
let(:namespace) { create(:namespace) }
let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
- let(:reference) { urls.namespace_project_commit_url(project2.namespace, project2, commit.id) }
+ let(:reference) { urls.project_commit_url(project2, commit.id) }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
+ .to eq urls.project_commit_url(project2, commit.id)
end
it 'links with adjacent text' do
diff --git a/spec/lib/banzai/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb
index 086a006c45f..10910f22d4a 100644
--- a/spec/lib/banzai/filter/emoji_filter_spec.rb
+++ b/spec/lib/banzai/filter/emoji_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::EmojiFilter, lib: true do
+describe Banzai::Filter::EmojiFilter do
include FilterSpecHelper
before do
diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
index a4bb043f8f1..a0d391d981c 100644
--- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
+describe Banzai::Filter::ExternalIssueReferenceFilter do
include FilterSpecHelper
def helper
@@ -88,12 +88,12 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
it 'queries the collection on the first call' do
expect_any_instance_of(Project).to receive(:default_issues_tracker?).once.and_call_original
- expect_any_instance_of(Project).to receive(:issue_reference_pattern).once.and_call_original
+ expect_any_instance_of(Project).to receive(:external_issue_reference_pattern).once.and_call_original
not_cached = reference_filter.call("look for #{reference}", { project: project })
expect_any_instance_of(Project).not_to receive(:default_issues_tracker?)
- expect_any_instance_of(Project).not_to receive(:issue_reference_pattern)
+ expect_any_instance_of(Project).not_to receive(:external_issue_reference_pattern)
cached = reference_filter.call("look for #{reference}", { project: project })
@@ -108,6 +108,11 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
let(:issue) { ExternalIssue.new("#123", project) }
let(:reference) { issue.to_reference }
+ before do
+ project.issues_enabled = false
+ project.save!
+ end
+
it_behaves_like "external issue tracker"
end
diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
index 0f8ec8de7a0..2a3c0cd78b8 100644
--- a/spec/lib/banzai/filter/external_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -17,7 +17,7 @@ shared_examples 'an external link with rel attribute' do
end
end
-describe Banzai::Filter::ExternalLinkFilter, lib: true do
+describe Banzai::Filter::ExternalLinkFilter do
include FilterSpecHelper
it 'ignores elements without an href attribute' do
diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
index 082c0d4dd0d..663e3514436 100644
--- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
+++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::GollumTagsFilter, lib: true do
+describe Banzai::Filter::GollumTagsFilter do
include FilterSpecHelper
let(:project) { create(:empty_project) }
@@ -22,7 +22,7 @@ describe Banzai::Filter::GollumTagsFilter, lib: true do
tag = '[[images/image.jpg]]'
doc = filter("See #{tag}", project_wiki: project_wiki)
- expect(doc.at_css('img')['src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg"
+ expect(doc.at_css('img')['data-src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg"
end
it 'does not creates img tag if image does not exist' do
@@ -40,7 +40,7 @@ describe Banzai::Filter::GollumTagsFilter, lib: true do
tag = '[[http://example.com/image.jpg]]'
doc = filter("See #{tag}", project_wiki: project_wiki)
- expect(doc.at_css('img')['src']).to eq "http://example.com/image.jpg"
+ expect(doc.at_css('img')['data-src']).to eq "http://example.com/image.jpg"
end
it 'does not creates img tag for invalid URL' do
diff --git a/spec/lib/banzai/filter/html_entity_filter_spec.rb b/spec/lib/banzai/filter/html_entity_filter_spec.rb
index f9e6bd609f0..91e18d876d5 100644
--- a/spec/lib/banzai/filter/html_entity_filter_spec.rb
+++ b/spec/lib/banzai/filter/html_entity_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::HtmlEntityFilter, lib: true do
+describe Banzai::Filter::HtmlEntityFilter do
include FilterSpecHelper
let(:unescaped) { 'foo <strike attr="foo">&&&</strike>' }
diff --git a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
new file mode 100644
index 00000000000..c19de7b784a
--- /dev/null
+++ b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Banzai::Filter::ImageLazyLoadFilter, lib: true do
+ include FilterSpecHelper
+
+ def image(path)
+ %(<img src="#{path}" />)
+ end
+
+ it 'transforms the image src to a data-src' do
+ doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('img')['data-src']).to eq '/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'
+ end
+
+ it 'works with external images' do
+ doc = filter(image('https://i.imgur.com/DfssX9C.jpg'))
+ expect(doc.at_css('img')['data-src']).to eq 'https://i.imgur.com/DfssX9C.jpg'
+ end
+end
diff --git a/spec/lib/banzai/filter/image_link_filter_spec.rb b/spec/lib/banzai/filter/image_link_filter_spec.rb
index 294558b3db2..51920869545 100644
--- a/spec/lib/banzai/filter/image_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/image_link_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::ImageLinkFilter, lib: true do
+describe Banzai::Filter::ImageLinkFilter do
include FilterSpecHelper
def image(path)
diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
index 9e526371294..63c4ab61b86 100644
--- a/spec/lib/banzai/filter/inline_diff_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::InlineDiffFilter, lib: true do
+describe Banzai::Filter::InlineDiffFilter do
include FilterSpecHelper
it 'adds inline diff span tags for deletions when using square brackets' do
diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb
index 9c2399815b9..bc7cae1df8d 100644
--- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb
+++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::IssuableStateFilter, lib: true do
+describe Banzai::Filter::IssuableStateFilter do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
@@ -107,14 +107,6 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
expect(doc.css('a').last.text).to eq(issue.to_reference)
end
- it 'ignores reopened issue references' do
- issue = create_issue(:reopened)
- link = create_link(issue.to_reference, issue: issue.id, reference_type: 'issue')
- doc = filter(link, context)
-
- expect(doc.css('a').last.text).to eq(issue.to_reference)
- end
-
it 'appends state to closed issue references' do
link = create_link(closed_issue.to_reference, issue: closed_issue.id, reference_type: 'issue')
doc = filter(link, context)
@@ -139,7 +131,7 @@ describe Banzai::Filter::IssuableStateFilter, lib: true do
end
it 'ignores reopened merge request references' do
- merge_request = create_merge_request(:reopened)
+ merge_request = create_merge_request(:opened)
link = create_link(
merge_request.to_reference,
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index e5c1deb338b..045bf3e0cc9 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::IssueReferenceFilter, lib: true do
+describe Banzai::Filter::IssueReferenceFilter do
include FilterSpecHelper
def helper
@@ -39,13 +39,6 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
let(:reference) { "##{issue.iid}" }
- it 'ignores valid references when using non-default tracker' do
- allow(project).to receive(:default_issues_tracker?).and_return(false)
-
- exp = act = "Issue #{reference}"
- expect(reference_filter(act).to_html).to eq exp
- end
-
it 'links to a valid reference' do
doc = reference_filter("Fixed #{reference}")
@@ -340,24 +333,6 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
.to eq({ project => { issue.iid => issue } })
end
end
-
- context 'using an external issue tracker' do
- it 'returns a Hash containing the issues per project' do
- doc = Nokogiri::HTML.fragment('')
- filter = described_class.new(doc, project: project)
-
- expect(project).to receive(:default_issues_tracker?).and_return(false)
-
- expect(filter).to receive(:projects_per_reference)
- .and_return({ project.path_with_namespace => project })
-
- expect(filter).to receive(:references_per_project)
- .and_return({ project.path_with_namespace => Set.new([1]) })
-
- expect(filter.issues_per_project[project][1])
- .to be_an_instance_of(ExternalIssue)
- end
- end
end
describe '.references_in' do
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index cb3cf982351..1daa6ac7f9e 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'html/pipeline'
-describe Banzai::Filter::LabelReferenceFilter, lib: true do
+describe Banzai::Filter::LabelReferenceFilter do
include FilterSpecHelper
let(:project) { create(:empty_project, :public, name: 'sample-project') }
@@ -45,7 +45,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
link = doc.css('a').first.attr('href')
expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_issues_path(project.namespace, project, label_name: label.name)
+ expect(link).to eq urls.project_issues_path(project, label_name: label.name)
end
context 'project that does not exist referenced' do
@@ -73,7 +73,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
end
it 'links with adjacent text' do
@@ -96,7 +96,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
expect(doc.text).to eq 'See gfm'
end
@@ -120,7 +120,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
expect(doc.text).to eq 'See 2fa'
end
@@ -144,7 +144,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
expect(doc.text).to eq 'See ?g.fm&'
end
@@ -169,7 +169,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
expect(doc.text).to eq 'See gfm references'
end
@@ -193,7 +193,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
expect(doc.text).to eq 'See 2 factor authentication'
end
@@ -217,7 +217,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
expect(doc.text).to eq 'See g.fm & references?'
end
@@ -250,9 +250,9 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{references}")
expect(doc.css('a').map { |a| a.attr('href') }).to match_array([
- urls.namespace_project_issues_url(project.namespace, project, label_name: bug.name),
- urls.namespace_project_issues_url(project.namespace, project, label_name: feature_proposal.name),
- urls.namespace_project_issues_url(project.namespace, project, label_name: technical_debt.name)
+ urls.project_issues_url(project, label_name: bug.name),
+ urls.project_issues_url(project, label_name: feature_proposal.name),
+ urls.project_issues_url(project, label_name: technical_debt.name)
])
expect(doc.text).to eq 'See bug, feature proposal, technical debt'
end
@@ -265,9 +265,9 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{references}")
expect(doc.css('a').map { |a| a.attr('href') }).to match_array([
- urls.namespace_project_issues_url(project.namespace, project, label_name: bug.name),
- urls.namespace_project_issues_url(project.namespace, project, label_name: feature_proposal.name),
- urls.namespace_project_issues_url(project.namespace, project, label_name: technical_debt.name)
+ urls.project_issues_url(project, label_name: bug.name),
+ urls.project_issues_url(project, label_name: feature_proposal.name),
+ urls.project_issues_url(project, label_name: technical_debt.name)
])
expect(doc.text).to eq 'See bug feature proposal technical debt'
end
@@ -288,7 +288,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ .project_issues_url(project, label_name: label.name)
end
it 'links with adjacent text' do
@@ -325,7 +325,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}", project: project)
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: group_label.name)
+ .project_issues_url(project, label_name: group_label.name)
expect(doc.text).to eq 'See gfm references'
end
@@ -348,7 +348,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
doc = reference_filter("See #{reference}", project: project)
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_issues_url(project.namespace, project, label_name: group_label.name)
+ .project_issues_url(project, label_name: group_label.name)
expect(doc.text).to eq "See gfm references"
end
@@ -373,9 +373,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'links to a valid reference' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(project2.namespace,
- project2,
- label_name: label.name)
+ .to eq urls.project_issues_url(project2, label_name: label.name)
end
it 'has valid color' do
@@ -407,9 +405,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'links to a valid reference' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(project2.namespace,
- project2,
- label_name: label.name)
+ .to eq urls.project_issues_url(project2, label_name: label.name)
end
it 'has valid color' do
@@ -441,9 +437,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'links to a valid reference' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(project2.namespace,
- project2,
- label_name: label.name)
+ .to eq urls.project_issues_url(project2, label_name: label.name)
end
it 'has valid color' do
@@ -477,9 +471,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'points to referenced project issues page' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(another_project.namespace,
- another_project,
- label_name: group_label.name)
+ .to eq urls.project_issues_url(another_project, label_name: group_label.name)
end
it 'has valid color' do
@@ -514,9 +506,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'points to referenced project issues page' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(another_project.namespace,
- another_project,
- label_name: group_label.name)
+ .to eq urls.project_issues_url(another_project, label_name: group_label.name)
end
it 'has valid color' do
@@ -550,9 +540,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'points to referenced project issues page' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(project.namespace,
- project,
- label_name: group_label.name)
+ .to eq urls.project_issues_url(project, label_name: group_label.name)
end
it 'has valid color' do
@@ -584,9 +572,7 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
it 'points to referenced project issues page' do
expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(project.namespace,
- project,
- label_name: group_label.name)
+ .to eq urls.project_issues_url(project, label_name: group_label.name)
end
it 'has valid color' do
diff --git a/spec/lib/banzai/filter/markdown_filter_spec.rb b/spec/lib/banzai/filter/markdown_filter_spec.rb
index 897288b8ad5..00c407d1b69 100644
--- a/spec/lib/banzai/filter/markdown_filter_spec.rb
+++ b/spec/lib/banzai/filter/markdown_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::MarkdownFilter, lib: true do
+describe Banzai::Filter::MarkdownFilter do
include FilterSpecHelper
context 'code block' do
diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb
index 51883782e19..cade8cb409e 100644
--- a/spec/lib/banzai/filter/math_filter_spec.rb
+++ b/spec/lib/banzai/filter/math_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::MathFilter, lib: true do
+describe Banzai::Filter::MathFilter do
include FilterSpecHelper
it 'leaves regular inline code unchanged' do
diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
index cd91681551e..683972a3112 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
+describe Banzai::Filter::MergeRequestReferenceFilter do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
@@ -37,7 +37,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_merge_request_url(project.namespace, project, merge)
+ .project_merge_request_url(project, merge)
end
it 'links with adjacent text' do
@@ -95,7 +95,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
link = doc.css('a').first.attr('href')
expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_merge_request_url(project.namespace, project, merge, only_path: true)
+ expect(link).to eq urls.project_merge_request_url(project, merge, only_path: true)
end
end
@@ -108,8 +108,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_merge_request_url(project2.namespace,
- project2, merge)
+ .to eq urls.project_merge_request_url(project2, merge)
end
it 'link has valid text' do
@@ -142,8 +141,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_merge_request_url(project2.namespace,
- project2, merge)
+ .to eq urls.project_merge_request_url(project2, merge)
end
it 'link has valid text' do
@@ -176,8 +174,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_merge_request_url(project2.namespace,
- project2, merge)
+ .to eq urls.project_merge_request_url(project2, merge)
end
it 'link has valid text' do
@@ -203,7 +200,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
let(:namespace) { create(:namespace, name: 'cross-reference') }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:merge) { create(:merge_request, source_project: project2, target_project: project2) }
- let(:reference) { urls.namespace_project_merge_request_url(project2.namespace, project2, merge) + '/diffs#note_123' }
+ let(:reference) { urls.project_merge_request_url(project2, merge) + '/diffs#note_123' }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index fe88b9cb73e..8fe05dc2e53 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
+describe Banzai::Filter::MilestoneReferenceFilter do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
@@ -45,7 +45,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
expect(link).not_to match %r(https?://)
expect(link).to eq urls
- .namespace_project_milestone_path(project.namespace, project, milestone)
+ .project_milestone_path(project, milestone)
end
context 'Integer-based references' do
@@ -53,7 +53,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(project.namespace, project, milestone)
+ .project_milestone_url(project, milestone)
end
it 'links with adjacent text' do
@@ -76,7 +76,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(project.namespace, project, milestone)
+ .project_milestone_url(project, milestone)
expect(doc.text).to eq 'See gfm'
end
@@ -100,7 +100,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(project.namespace, project, milestone)
+ .project_milestone_url(project, milestone)
expect(doc.text).to eq 'See gfm references'
end
@@ -123,7 +123,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(project.namespace, project, milestone)
+ .project_milestone_url(project, milestone)
end
it 'links with adjacent text' do
@@ -157,9 +157,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(another_project.namespace,
- another_project,
- milestone)
+ .project_milestone_url(another_project, milestone)
end
it 'link has valid text' do
@@ -196,9 +194,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(another_project.namespace,
- another_project,
- milestone)
+ .project_milestone_url(another_project, milestone)
end
it 'link has valid text' do
@@ -235,9 +231,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls
- .namespace_project_milestone_url(another_project.namespace,
- another_project,
- milestone)
+ .project_milestone_url(another_project, milestone)
end
it 'link has valid text' do
diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb
index 9b8ecb201f3..8235c411eb7 100644
--- a/spec/lib/banzai/filter/plantuml_filter_spec.rb
+++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::PlantumlFilter, lib: true do
+describe Banzai::Filter::PlantumlFilter do
include FilterSpecHelper
it 'should replace plantuml pre tag with img tag' do
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index b81cdbb8957..fb6b81d4f10 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::RedactorFilter, lib: true do
+describe Banzai::Filter::RedactorFilter do
include ActionView::Helpers::UrlHelper
include FilterSpecHelper
diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb
index ba0fa4a609a..b9ca68e8935 100644
--- a/spec/lib/banzai/filter/reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::ReferenceFilter, lib: true do
+describe Banzai::Filter::ReferenceFilter do
let(:project) { build(:project) }
describe '#each_node' do
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index 1ce7bd7706e..ddebf2264d9 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::RelativeLinkFilter, lib: true do
+describe Banzai::Filter::RelativeLinkFilter do
def filter(doc, contexts = {})
contexts.reverse_merge!({
commit: commit,
diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
index a8a0aa6d395..35a32a46eff 100644
--- a/spec/lib/banzai/filter/sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::SanitizationFilter, lib: true do
+describe Banzai::Filter::SanitizationFilter do
include FilterSpecHelper
describe 'default whitelist' do
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index e851120bc3a..5f548888223 100644
--- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::SnippetReferenceFilter, lib: true do
+describe Banzai::Filter::SnippetReferenceFilter do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
@@ -23,7 +23,7 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls
- .namespace_project_snippet_url(project.namespace, project, snippet)
+ .project_snippet_url(project, snippet)
end
it 'links with adjacent text' do
@@ -75,7 +75,7 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
link = doc.css('a').first.attr('href')
expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_snippet_url(project.namespace, project, snippet, only_path: true)
+ expect(link).to eq urls.project_snippet_url(project, snippet, only_path: true)
end
end
@@ -89,7 +89,7 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ .to eq urls.project_snippet_url(project2, snippet)
end
it 'link has valid text' do
@@ -122,7 +122,7 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ .to eq urls.project_snippet_url(project2, snippet)
end
it 'link has valid text' do
@@ -155,7 +155,7 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ .to eq urls.project_snippet_url(project2, snippet)
end
it 'link has valid text' do
@@ -181,13 +181,13 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
let(:namespace) { create(:namespace, name: 'cross-reference') }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:snippet) { create(:project_snippet, project: project2) }
- let(:reference) { urls.namespace_project_snippet_url(project2.namespace, project2, snippet) }
+ let(:reference) { urls.project_snippet_url(project2, snippet) }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ .to eq urls.project_snippet_url(project2, snippet)
end
it 'links with adjacent text' do
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index f61fc8ceb9e..5a23e0e70cc 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
+describe Banzai::Filter::SyntaxHighlightFilter do
include FilterSpecHelper
context "when no language is specified" do
diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
index 70b31f3a880..ff6b19459bb 100644
--- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
+++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::TableOfContentsFilter, lib: true do
+describe Banzai::Filter::TableOfContentsFilter do
include FilterSpecHelper
def header(level, text)
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index 6327ca8bbfd..3bc9635b50e 100644
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::UploadLinkFilter, lib: true do
+describe Banzai::Filter::UploadLinkFilter do
def filter(doc, contexts = {})
contexts.reverse_merge!({
project: project
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index edf3846b742..7ea9df5eda5 100644
--- a/spec/lib/banzai/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::UserReferenceFilter, lib: true do
+describe Banzai::Filter::UserReferenceFilter do
include FilterSpecHelper
let(:project) { create(:empty_project, :public) }
@@ -43,7 +43,7 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
expect(doc.css('a').length).to eq 1
expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_url(project.namespace, project)
+ .to eq urls.project_url(project)
end
it 'includes a data-author attribute when there is an author' do
diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb
index 00494f545a3..81dda0687f3 100644
--- a/spec/lib/banzai/filter/video_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/video_link_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::VideoLinkFilter, lib: true do
+describe Banzai::Filter::VideoLinkFilter do
def filter(doc, contexts = {})
contexts.reverse_merge!({
project: project
diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
index 92d88c4172c..ceafd12a68e 100644
--- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::Filter::WikiLinkFilter, lib: true do
+describe Banzai::Filter::WikiLinkFilter do
include FilterSpecHelper
let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") }
diff --git a/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb b/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb
index fe70eada7eb..9f1b862ef19 100644
--- a/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb
+++ b/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Banzai::Filter::YamlFrontMatterFilter, lib: true do
+describe Banzai::Filter::YamlFrontMatterFilter do
include FilterSpecHelper
it 'allows for `encoding:` before the frontmatter' do
diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb
index 866297f94a9..728271e757b 100644
--- a/spec/lib/banzai/issuable_extractor_spec.rb
+++ b/spec/lib/banzai/issuable_extractor_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::IssuableExtractor, lib: true do
+describe Banzai::IssuableExtractor do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:extractor) { described_class.new(project, user) }
diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
new file mode 100644
index 00000000000..601ffbb5456
--- /dev/null
+++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb
@@ -0,0 +1,90 @@
+require 'rails_helper'
+
+describe Banzai::Pipeline::GfmPipeline do
+ describe 'integration between parsing regular and external issue references' do
+ let(:project) { create(:redmine_project, :public) }
+
+ context 'when internal issue tracker is enabled' do
+ context 'when shorthand pattern #ISSUE_ID is used' do
+ it 'links an internal issue if it exists' do
+ issue = create(:issue, project: project)
+ markdown = issue.to_reference(project, full: true)
+
+ result = described_class.call(markdown, project: project)[:output]
+ link = result.css('a').first
+
+ expect(link['href']).to eq(
+ Gitlab::Routing.url_helpers.project_issue_path(project, issue)
+ )
+ end
+
+ it 'does not link any issue if it does not exist on GitLab' do
+ markdown = '#12'
+
+ result = described_class.call(markdown, project: project)[:output]
+ expect(result.css('a')).to be_empty
+ end
+ end
+
+ it 'allows to use long external reference syntax for Redmine' do
+ markdown = 'API_32-12'
+
+ result = described_class.call(markdown, project: project)[:output]
+ link = result.css('a').first
+
+ expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12'
+ end
+
+ it 'parses cross-project references to regular issues' do
+ other_project = create(:empty_project, :public)
+ issue = create(:issue, project: other_project)
+ markdown = issue.to_reference(project, full: true)
+
+ result = described_class.call(markdown, project: project)[:output]
+ link = result.css('a').first
+
+ expect(link['href']).to eq(
+ Gitlab::Routing.url_helpers.project_issue_path(other_project, issue)
+ )
+ end
+ end
+
+ context 'when internal issue tracker is disabled' do
+ before do
+ project.issues_enabled = false
+ project.save!
+ end
+
+ it 'allows to use shorthand external reference syntax for Redmine' do
+ markdown = '#12'
+
+ result = described_class.call(markdown, project: project)[:output]
+ link = result.css('a').first
+
+ expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12'
+ end
+
+ it 'allows to use long external reference syntax for Redmine' do
+ markdown = 'API_32-12'
+
+ result = described_class.call(markdown, project: project)[:output]
+ link = result.css('a').first
+
+ expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12'
+ end
+
+ it 'parses cross-project references to regular issues' do
+ other_project = create(:empty_project, :public)
+ issue = create(:issue, project: other_project)
+ markdown = issue.to_reference(project, full: true)
+
+ result = described_class.call(markdown, project: project)[:output]
+ link = result.css('a').first
+
+ expect(link['href']).to eq(
+ Gitlab::Routing.url_helpers.project_issue_path(other_project, issue)
+ )
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index b444ca05b8e..0bf45329657 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::BaseParser, lib: true do
+describe Banzai::ReferenceParser::BaseParser do
include ReferenceParserHelpers
let(:user) { create(:user) }
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
index a314a6119cb..69bf28cdf85 100644
--- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::CommitParser, lib: true do
+describe Banzai::ReferenceParser::CommitParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
index 5dca5e784da..b384a59bfb4 100644
--- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::CommitRangeParser, lib: true do
+describe Banzai::ReferenceParser::CommitRangeParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
index d212bbac619..a3256afdbb1 100644
--- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do
+describe Banzai::ReferenceParser::ExternalIssueParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
index 58e1a0c1bc1..94b989fe91d 100644
--- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::IssueParser, lib: true do
+describe Banzai::ReferenceParser::IssueParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
@@ -39,16 +39,6 @@ describe Banzai::ReferenceParser::IssueParser, lib: true do
expect(subject.nodes_visible_to_user(user, [link])).to eq([])
end
end
-
- context 'when the project uses an external issue tracker' do
- it 'returns all nodes' do
- link = double(:link)
-
- expect(project).to receive(:external_issue_tracker).and_return(true)
-
- expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
- end
- end
end
describe '#referenced_by' do
diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb
index ddd699f3c25..cf1b2a92195 100644
--- a/spec/lib/banzai/reference_parser/label_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::LabelParser, lib: true do
+describe Banzai::ReferenceParser::LabelParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
index cb69ca16800..775749ae3a7 100644
--- a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MergeRequestParser, lib: true do
+describe Banzai::ReferenceParser::MergeRequestParser do
include ReferenceParserHelpers
let(:user) { create(:user) }
diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
index 72d4f3bc18e..2cfcafa8798 100644
--- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::MilestoneParser, lib: true do
+describe Banzai::ReferenceParser::MilestoneParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
index 620875ece20..c6d0b7be254 100644
--- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::SnippetParser, lib: true do
+describe Banzai::ReferenceParser::SnippetParser do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index dfebb971f3a..64f2b607d7c 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Banzai::ReferenceParser::UserParser, lib: true do
+describe Banzai::ReferenceParser::UserParser do
include ReferenceParserHelpers
let(:group) { create(:group) }
diff --git a/spec/lib/ci/ansi2html_spec.rb b/spec/lib/ci/ansi2html_spec.rb
index a5dfb49478a..e49ecadde20 100644
--- a/spec/lib/ci/ansi2html_spec.rb
+++ b/spec/lib/ci/ansi2html_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Ansi2html, lib: true do
+describe Ci::Ansi2html do
subject { described_class }
it "prints non-ansi as-is" do
diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb
index fb6cc398307..8e2d2724426 100644
--- a/spec/lib/ci/charts_spec.rb
+++ b/spec/lib/ci/charts_spec.rb
@@ -1,21 +1,21 @@
require 'spec_helper'
-describe Ci::Charts, lib: true do
- context "build_times" do
+describe Ci::Charts do
+ context "pipeline_times" do
let(:project) { create(:empty_project) }
- let(:chart) { Ci::Charts::BuildTime.new(project) }
+ let(:chart) { Ci::Charts::PipelineTime.new(project) }
- subject { chart.build_times }
+ subject { chart.pipeline_times }
before do
create(:ci_empty_pipeline, project: project, duration: 120)
end
- it 'returns build times in minutes' do
+ it 'returns pipeline times in minutes' do
is_expected.to contain_exactly(2)
end
- it 'handles nil build times' do
+ it 'handles nil pipeline times' do
create(:ci_empty_pipeline, project: project, duration: nil)
is_expected.to contain_exactly(2, 0)
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index af0e7855a9b..ed571a2ba05 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -32,6 +32,28 @@ module Ci
end
end
+ describe 'retry entry' do
+ context 'when retry count is specified' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec', retry: 1 })
+ end
+
+ it 'includes retry count in build options attribute' do
+ expect(subject[:options]).to include(retry: 1)
+ end
+ end
+
+ context 'when retry count is not specified' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec' })
+ end
+
+ it 'does not persist retry count in the database' do
+ expect(subject[:options]).not_to have_key(:retry)
+ end
+ end
+ end
+
describe 'allow failure entry' do
context 'when job is a manual action' do
context 'when allow_failure is defined' do
@@ -163,7 +185,10 @@ module Ci
commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
- options: {},
+ options: {
+ before_script: ["pwd"],
+ script: ["rspec"]
+ },
allow_failure: false,
when: "on_success",
environment: nil,
@@ -598,8 +623,10 @@ module Ci
describe "Image and service handling" do
context "when extended docker configuration is used" do
it "returns image and service when defined" do
- config = YAML.dump({ image: { name: "ruby:2.1" },
- services: ["mysql", { name: "docker:dind", alias: "docker" }],
+ config = YAML.dump({ image: { name: "ruby:2.1", entrypoint: ["/usr/local/bin/init", "run"] },
+ services: ["mysql", { name: "docker:dind", alias: "docker",
+ entrypoint: ["/usr/local/bin/init", "run"],
+ command: ["/usr/local/bin/init", "run"] }],
before_script: ["pwd"],
rspec: { script: "rspec" } })
@@ -614,8 +641,12 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
- image: { name: "ruby:2.1" },
- services: [{ name: "mysql" }, { name: "docker:dind", alias: "docker" }]
+ before_script: ["pwd"],
+ script: ["rspec"],
+ image: { name: "ruby:2.1", entrypoint: ["/usr/local/bin/init", "run"] },
+ services: [{ name: "mysql" },
+ { name: "docker:dind", alias: "docker", entrypoint: ["/usr/local/bin/init", "run"],
+ command: ["/usr/local/bin/init", "run"] }]
},
allow_failure: false,
when: "on_success",
@@ -628,8 +659,11 @@ module Ci
config = YAML.dump({ image: "ruby:2.1",
services: ["mysql"],
before_script: ["pwd"],
- rspec: { image: { name: "ruby:2.5" },
- services: [{ name: "postgresql", alias: "db-pg" }, "docker:dind"], script: "rspec" } })
+ rspec: { image: { name: "ruby:2.5", entrypoint: ["/usr/local/bin/init", "run"] },
+ services: [{ name: "postgresql", alias: "db-pg",
+ entrypoint: ["/usr/local/bin/init", "run"],
+ command: ["/usr/local/bin/init", "run"] }, "docker:dind"],
+ script: "rspec" } })
config_processor = GitlabCiYamlProcessor.new(config, path)
@@ -642,8 +676,12 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
- image: { name: "ruby:2.5" },
- services: [{ name: "postgresql", alias: "db-pg" }, { name: "docker:dind" }]
+ before_script: ["pwd"],
+ script: ["rspec"],
+ image: { name: "ruby:2.5", entrypoint: ["/usr/local/bin/init", "run"] },
+ services: [{ name: "postgresql", alias: "db-pg", entrypoint: ["/usr/local/bin/init", "run"],
+ command: ["/usr/local/bin/init", "run"] },
+ { name: "docker:dind" }]
},
allow_failure: false,
when: "on_success",
@@ -671,6 +709,8 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
+ before_script: ["pwd"],
+ script: ["rspec"],
image: { name: "ruby:2.1" },
services: [{ name: "mysql" }, { name: "docker:dind" }]
},
@@ -698,8 +738,10 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
- image: { name: "ruby:2.5" },
- services: [{ name: "postgresql" }, { name: "docker:dind" }]
+ before_script: ["pwd"],
+ script: ["rspec"],
+ image: { name: "ruby:2.5" },
+ services: [{ name: "postgresql" }, { name: "docker:dind" }]
},
allow_failure: false,
when: "on_success",
@@ -869,7 +911,8 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"],
untracked: true,
- key: 'key'
+ key: 'key',
+ policy: 'pull-push'
)
end
@@ -887,7 +930,8 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"],
untracked: true,
- key: 'key'
+ key: 'key',
+ policy: 'pull-push'
)
end
@@ -906,7 +950,8 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
paths: ["test/"],
untracked: false,
- key: 'local'
+ key: 'local',
+ policy: 'pull-push'
)
end
end
@@ -939,6 +984,8 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
+ before_script: ["pwd"],
+ script: ["rspec"],
image: { name: "ruby:2.1" },
services: [{ name: "mysql" }],
artifacts: {
@@ -1150,7 +1197,9 @@ module Ci
commands: "test",
coverage_regex: nil,
tag_list: [],
- options: {},
+ options: {
+ script: ["test"]
+ },
when: "on_success",
allow_failure: false,
environment: nil,
@@ -1196,7 +1245,9 @@ module Ci
commands: "execute-script-for-job",
coverage_regex: nil,
tag_list: [],
- options: {},
+ options: {
+ script: ["execute-script-for-job"]
+ },
when: "on_success",
allow_failure: false,
environment: nil,
@@ -1209,7 +1260,9 @@ module Ci
commands: "execute-script-for-job",
coverage_regex: nil,
tag_list: [],
- options: {},
+ options: {
+ script: ["execute-script-for-job"]
+ },
when: "on_success",
allow_failure: false,
environment: nil,
diff --git a/spec/lib/ci/mask_secret_spec.rb b/spec/lib/ci/mask_secret_spec.rb
index 3101bed20fb..f7b753b022b 100644
--- a/spec/lib/ci/mask_secret_spec.rb
+++ b/spec/lib/ci/mask_secret_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::MaskSecret, lib: true do
+describe Ci::MaskSecret do
subject { described_class }
describe '#mask' do
diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb
index db680489a8d..4dab58b26a0 100644
--- a/spec/lib/constraints/group_url_constrainer_spec.rb
+++ b/spec/lib/constraints/group_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupUrlConstrainer, lib: true do
+describe GroupUrlConstrainer do
let!(:group) { create(:group, path: 'gitlab') }
describe '#matches?' do
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index b6884e37aa3..e4b5dfc574a 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectUrlConstrainer, lib: true do
+describe ProjectUrlConstrainer do
let!(:project) { create(:empty_project) }
let!(:namespace) { project.namespace }
diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb
index ed69b830979..cb3b4ff1391 100644
--- a/spec/lib/constraints/user_url_constrainer_spec.rb
+++ b/spec/lib/constraints/user_url_constrainer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UserUrlConstrainer, lib: true do
+describe UserUrlConstrainer do
let!(:user) { create(:user, username: 'dz') }
describe '#matches?' do
diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb
index 8f51474476d..3652d928c43 100644
--- a/spec/lib/disable_email_interceptor_spec.rb
+++ b/spec/lib/disable_email_interceptor_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe DisableEmailInterceptor, lib: true do
+describe DisableEmailInterceptor do
before do
- Mail.register_interceptor(DisableEmailInterceptor)
+ Mail.register_interceptor(described_class)
end
it 'does not send emails' do
@@ -14,7 +14,7 @@ describe DisableEmailInterceptor, lib: true do
# Removing interceptor from the list because unregister_interceptor is
# implemented in later version of mail gem
# See: https://github.com/mikel/mail/pull/705
- Mail.unregister_interceptor(DisableEmailInterceptor)
+ Mail.unregister_interceptor(described_class)
end
def deliver_mail
diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb
index d70690f589d..b1366e74802 100644
--- a/spec/lib/event_filter_spec.rb
+++ b/spec/lib/event_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe EventFilter, lib: true do
+describe EventFilter do
describe '#apply_filter' do
let(:source_user) { create(:user) }
let!(:public_project) { create(:empty_project, :public) }
@@ -16,42 +16,42 @@ describe EventFilter, lib: true do
let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) }
it 'applies push filter' do
- events = EventFilter.new(EventFilter.push).apply_filter(Event.all)
+ events = described_class.new(described_class.push).apply_filter(Event.all)
expect(events).to contain_exactly(push_event)
end
it 'applies merged filter' do
- events = EventFilter.new(EventFilter.merged).apply_filter(Event.all)
+ events = described_class.new(described_class.merged).apply_filter(Event.all)
expect(events).to contain_exactly(merged_event)
end
it 'applies issue filter' do
- events = EventFilter.new(EventFilter.issue).apply_filter(Event.all)
+ events = described_class.new(described_class.issue).apply_filter(Event.all)
expect(events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
end
it 'applies comments filter' do
- events = EventFilter.new(EventFilter.comments).apply_filter(Event.all)
+ events = described_class.new(described_class.comments).apply_filter(Event.all)
expect(events).to contain_exactly(comments_event)
end
it 'applies team filter' do
- events = EventFilter.new(EventFilter.team).apply_filter(Event.all)
+ events = described_class.new(described_class.team).apply_filter(Event.all)
expect(events).to contain_exactly(joined_event, left_event)
end
it 'applies all filter' do
- events = EventFilter.new(EventFilter.all).apply_filter(Event.all)
+ events = described_class.new(described_class.all).apply_filter(Event.all)
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
end
it 'applies no filter' do
- events = EventFilter.new(nil).apply_filter(Event.all)
+ events = described_class.new(nil).apply_filter(Event.all)
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
end
it 'applies unknown filter' do
- events = EventFilter.new('').apply_filter(Event.all)
+ events = described_class.new('').apply_filter(Event.all)
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
end
end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index f2132d485ab..9b89f47ae7e 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe ExtractsPath, lib: true do
- include ExtractsPath
+describe ExtractsPath do
+ include described_class
include RepoHelpers
- include Gitlab::Routing.url_helpers
+ include Gitlab::Routing
let(:project) { double('project') }
let(:request) { double('request') }
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index 5cc3a3745e4..1076c63b5f2 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Feature, lib: true do
+describe Feature do
describe '.get' do
let(:feature) { double(:feature) }
let(:key) { 'my_feature' }
diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb
index fda6f9a6c88..49501931dd2 100644
--- a/spec/lib/file_size_validator_spec.rb
+++ b/spec/lib/file_size_validator_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe FileSizeValidator, lib: true do
- let(:validator) { FileSizeValidator.new(options) }
+describe FileSizeValidator do
+ let(:validator) { described_class.new(options) }
let(:attachment) { AttachmentUploader.new }
let(:note) { create(:note) }
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 43d52b941ab..f668f78c2b8 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
require 'nokogiri'
module Gitlab
- describe Asciidoc, lib: true do
+ describe Asciidoc do
let(:input) { '<b>ascii</b>' }
let(:context) { {} }
let(:html) { 'H<sub>2</sub>O' }
diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
index fc72df575be..f29431b937c 100644
--- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
+++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Auth::UniqueIpsLimiter, :redis, lib: true do
+describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state do
include_context 'unique ips sign in limit'
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index d09da951869..a9db0d5164d 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Auth, lib: true do
+describe Gitlab::Auth do
let(:gl_auth) { described_class }
describe 'constants' do
@@ -206,7 +206,7 @@ describe Gitlab::Auth, lib: true do
end
it 'throws an error suggesting user create a PAT when internal auth is disabled' do
- allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false }
+ allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled?) { false }
expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalTokenError)
end
@@ -279,6 +279,16 @@ describe Gitlab::Auth, lib: true do
gl_auth.find_with_user_password('ldap_user', 'password')
end
end
+
+ context "with sign-in disabled" do
+ before do
+ stub_application_setting(password_authentication_enabled: false)
+ end
+
+ it "does not find user by valid login/password" do
+ expect(gl_auth.find_with_user_password(username, password)).to be_nil
+ end
+ end
end
private
diff --git a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb
new file mode 100644
index 00000000000..a910fb105a5
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::MigrateSystemUploadsToNewFolder do
+ let(:migration) { described_class.new }
+
+ before do
+ allow(migration).to receive(:logger).and_return(Logger.new(nil))
+ end
+
+ describe '#perform' do
+ it 'renames the path of system-uploads', truncate: true do
+ upload = create(:upload, model: create(:empty_project), path: 'uploads/system/project/avatar.jpg')
+
+ migration.perform('uploads/system/', 'uploads/-/system/')
+
+ expect(upload.reload.path).to eq('uploads/-/system/project/avatar.jpg')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration_spec.rb b/spec/lib/gitlab/background_migration_spec.rb
index 64f82fe27b2..4ad69aeba43 100644
--- a/spec/lib/gitlab/background_migration_spec.rb
+++ b/spec/lib/gitlab/background_migration_spec.rb
@@ -1,46 +1,120 @@
require 'spec_helper'
describe Gitlab::BackgroundMigration do
+ describe '.queue' do
+ it 'returns background migration worker queue' do
+ expect(described_class.queue)
+ .to eq BackgroundMigrationWorker.sidekiq_options['queue']
+ end
+ end
+
describe '.steal' do
- it 'steals jobs from a queue' do
- queue = [double(:job, args: ['Foo', [10, 20]])]
+ context 'when there are enqueued jobs present' do
+ let(:queue) do
+ [double(args: ['Foo', [10, 20]], queue: described_class.queue)]
+ end
+
+ before do
+ allow(Sidekiq::Queue).to receive(:new)
+ .with(described_class.queue)
+ .and_return(queue)
+ end
+
+ context 'when queue contains unprocessed jobs' do
+ it 'steals jobs from a queue' do
+ expect(queue[0]).to receive(:delete).and_return(true)
+
+ expect(described_class).to receive(:perform)
+ .with('Foo', [10, 20])
+
+ described_class.steal('Foo')
+ end
+
+ it 'does not steal job that has already been taken' do
+ expect(queue[0]).to receive(:delete).and_return(false)
+
+ expect(described_class).not_to receive(:perform)
+
+ described_class.steal('Foo')
+ end
+
+ it 'does not steal jobs for a different migration' do
+ expect(described_class).not_to receive(:perform)
- allow(Sidekiq::Queue).to receive(:new)
- .with(BackgroundMigrationWorker.sidekiq_options['queue'])
- .and_return(queue)
+ expect(queue[0]).not_to receive(:delete)
- expect(queue[0]).to receive(:delete)
+ described_class.steal('Bar')
+ end
+ end
- expect(described_class).to receive(:perform).with('Foo', [10, 20])
+ context 'when one of the jobs raises an error' do
+ let(:migration) { spy(:migration) }
- described_class.steal('Foo')
+ let(:queue) do
+ [double(args: ['Foo', [10, 20]], queue: described_class.queue),
+ double(args: ['Foo', [20, 30]], queue: described_class.queue)]
+ end
+
+ before do
+ stub_const("#{described_class}::Foo", migration)
+
+ allow(queue[0]).to receive(:delete).and_return(true)
+ allow(queue[1]).to receive(:delete).and_return(true)
+ end
+
+ it 'enqueues the migration again and re-raises the error' do
+ allow(migration).to receive(:perform).with(10, 20)
+ .and_raise(Exception, 'Migration error').once
+
+ expect(BackgroundMigrationWorker).to receive(:perform_async)
+ .with('Foo', [10, 20]).once
+
+ expect { described_class.steal('Foo') }.to raise_error(Exception)
+ end
+ end
end
- it 'does not steal jobs for a different migration' do
- queue = [double(:job, args: ['Foo', [10, 20]])]
+ context 'when there are scheduled jobs present', :sidekiq, :redis do
+ it 'steals all jobs from the scheduled sets' do
+ Sidekiq::Testing.disable! do
+ BackgroundMigrationWorker.perform_in(10.minutes, 'Object')
- allow(Sidekiq::Queue).to receive(:new)
- .with(BackgroundMigrationWorker.sidekiq_options['queue'])
- .and_return(queue)
+ expect(Sidekiq::ScheduledSet.new).to be_one
+ expect(described_class).to receive(:perform).with('Object', any_args)
- expect(described_class).not_to receive(:perform)
+ described_class.steal('Object')
- expect(queue[0]).not_to receive(:delete)
+ expect(Sidekiq::ScheduledSet.new).to be_none
+ end
+ end
+ end
- described_class.steal('Bar')
+ context 'when there are enqueued and scheduled jobs present', :sidekiq, :redis do
+ it 'steals from the scheduled sets queue first' do
+ Sidekiq::Testing.disable! do
+ expect(described_class).to receive(:perform)
+ .with('Object', [1]).ordered
+ expect(described_class).to receive(:perform)
+ .with('Object', [2]).ordered
+
+ BackgroundMigrationWorker.perform_async('Object', [2])
+ BackgroundMigrationWorker.perform_in(10.minutes, 'Object', [1])
+
+ described_class.steal('Object')
+ end
+ end
end
end
describe '.perform' do
- it 'performs a background migration' do
- instance = double(:instance)
- klass = double(:klass, new: instance)
+ let(:migration) { spy(:migration) }
- expect(described_class).to receive(:const_get)
- .with('Foo')
- .and_return(klass)
+ before do
+ stub_const("#{described_class.name}::Foo", migration)
+ end
- expect(instance).to receive(:perform).with(10, 20)
+ it 'performs a background migration' do
+ expect(migration).to receive(:perform).with(10, 20).once
described_class.perform('Foo', [10, 20])
end
diff --git a/spec/lib/gitlab/backup/manager_spec.rb b/spec/lib/gitlab/backup/manager_spec.rb
index 1c3d2547fec..8772d3d5ada 100644
--- a/spec/lib/gitlab/backup/manager_spec.rb
+++ b/spec/lib/gitlab/backup/manager_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Backup::Manager, lib: true do
+describe Backup::Manager do
include StubENV
let(:progress) { StringIO.new }
@@ -214,4 +214,56 @@ describe Backup::Manager, lib: true do
end
end
end
+
+ describe '#upload' do
+ let(:backup_file) { Tempfile.new('backup', Gitlab.config.backup.path) }
+ let(:backup_filename) { File.basename(backup_file.path) }
+
+ before do
+ allow(subject).to receive(:tar_file).and_return(backup_filename)
+
+ stub_backup_setting(
+ upload: {
+ connection: {
+ provider: 'AWS',
+ aws_access_key_id: 'id',
+ aws_secret_access_key: 'secret'
+ },
+ remote_directory: 'directory',
+ multipart_chunk_size: 104857600,
+ encryption: nil,
+ storage_class: nil
+ }
+ )
+
+ # the Fog mock only knows about directories we create explicitly
+ Fog.mock!
+ connection = ::Fog::Storage.new(Gitlab.config.backup.upload.connection.symbolize_keys)
+ connection.directories.create(key: Gitlab.config.backup.upload.remote_directory)
+ end
+
+ context 'target path' do
+ it 'uses the tar filename by default' do
+ expect_any_instance_of(Fog::Collection).to receive(:create)
+ .with(hash_including(key: backup_filename))
+ .and_return(true)
+
+ Dir.chdir(Gitlab.config.backup.path) do
+ subject.upload
+ end
+ end
+
+ it 'adds the DIRECTORY environment variable if present' do
+ stub_env('DIRECTORY', 'daily')
+
+ expect_any_instance_of(Fog::Collection).to receive(:create)
+ .with(hash_including(key: "daily/#{backup_filename}"))
+ .and_return(true)
+
+ Dir.chdir(Gitlab.config.backup.path) do
+ subject.upload
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb
index 51c1e9d657b..3af69daa585 100644
--- a/spec/lib/gitlab/backup/repository_spec.rb
+++ b/spec/lib/gitlab/backup/repository_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Backup::Repository, lib: true do
+describe Backup::Repository do
let(:progress) { StringIO.new }
let!(:project) { create(:empty_project) }
@@ -60,4 +60,58 @@ describe Backup::Repository, lib: true do
end
end
end
+
+ describe '#empty_repo?' do
+ context 'for a wiki' do
+ let(:wiki) { create(:project_wiki) }
+
+ context 'wiki repo has content' do
+ let!(:wiki_page) { create(:wiki_page, wiki: wiki) }
+
+ before do
+ wiki.repository.exists? # initial cache
+ end
+
+ context '`repository.exists?` is incorrectly cached as false' do
+ before do
+ repo = wiki.repository
+ repo.send(:cache).expire(:exists?)
+ repo.send(:cache).fetch(:exists?) { false }
+ repo.send(:instance_variable_set, :@exists, false)
+ end
+
+ it 'returns false, regardless of bad cache value' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey
+ end
+ end
+
+ context '`repository.exists?` is correctly cached as true' do
+ it 'returns false' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey
+ end
+ end
+ end
+
+ context 'wiki repo does not have content' do
+ context '`repository.exists?` is incorrectly cached as true' do
+ before do
+ repo = wiki.repository
+ repo.send(:cache).expire(:exists?)
+ repo.send(:cache).fetch(:exists?) { true }
+ repo.send(:instance_variable_set, :@exists, true)
+ end
+
+ it 'returns true, regardless of bad cache value' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy
+ end
+ end
+
+ context '`repository.exists?` is correctly cached as false' do
+ it 'returns true' do
+ expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/badge/build/metadata_spec.rb b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb
index 9df96ea04eb..d537ce8803c 100644
--- a/spec/lib/gitlab/badge/build/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
-describe Gitlab::Badge::Build::Metadata do
+describe Gitlab::Badge::Pipeline::Metadata do
let(:badge) { double(project: create(:empty_project), ref: 'feature') }
let(:metadata) { described_class.new(badge) }
@@ -9,13 +9,13 @@ describe Gitlab::Badge::Build::Metadata do
describe '#title' do
it 'returns build status title' do
- expect(metadata.title).to eq 'build status'
+ expect(metadata.title).to eq 'pipeline status'
end
end
describe '#image_url' do
it 'returns valid url' do
- expect(metadata.image_url).to include 'badges/feature/build.svg'
+ expect(metadata.image_url).to include 'badges/feature/pipeline.svg'
end
end
diff --git a/spec/lib/gitlab/badge/build/status_spec.rb b/spec/lib/gitlab/badge/pipeline/status_spec.rb
index 6abf4ca46a9..dc835375c66 100644
--- a/spec/lib/gitlab/badge/build/status_spec.rb
+++ b/spec/lib/gitlab/badge/pipeline/status_spec.rb
@@ -1,36 +1,35 @@
require 'spec_helper'
-describe Gitlab::Badge::Build::Status do
+describe Gitlab::Badge::Pipeline::Status do
let(:project) { create(:project, :repository) }
let(:sha) { project.commit.sha }
let(:branch) { 'master' }
let(:badge) { described_class.new(project, branch) }
describe '#entity' do
- it 'always says build' do
- expect(badge.entity).to eq 'build'
+ it 'always says pipeline' do
+ expect(badge.entity).to eq 'pipeline'
end
end
describe '#template' do
it 'returns badge template' do
- expect(badge.template.key_text).to eq 'build'
+ expect(badge.template.key_text).to eq 'pipeline'
end
end
describe '#metadata' do
it 'returns badge metadata' do
- expect(badge.metadata.image_url)
- .to include 'badges/master/build.svg'
+ expect(badge.metadata.image_url).to include 'badges/master/pipeline.svg'
end
end
- context 'build exists' do
- let!(:build) { create_build(project, sha, branch) }
+ context 'pipeline exists' do
+ let!(:pipeline) { create_pipeline(project, sha, branch) }
- context 'build success' do
+ context 'pipeline success' do
before do
- build.success!
+ pipeline.success!
end
describe '#status' do
@@ -40,9 +39,9 @@ describe Gitlab::Badge::Build::Status do
end
end
- context 'build failed' do
+ context 'pipeline failed' do
before do
- build.drop!
+ pipeline.drop!
end
describe '#status' do
@@ -54,10 +53,10 @@ describe Gitlab::Badge::Build::Status do
context 'when outdated pipeline for given ref exists' do
before do
- build.success!
+ pipeline.success!
- old_build = create_build(project, '11eeffdd', branch)
- old_build.drop!
+ old_pipeline = create_pipeline(project, '11eeffdd', branch)
+ old_pipeline.drop!
end
it 'does not take outdated pipeline into account' do
@@ -67,10 +66,10 @@ describe Gitlab::Badge::Build::Status do
context 'when multiple pipelines exist for given sha' do
before do
- build.drop!
+ pipeline.drop!
- new_build = create_build(project, sha, branch)
- new_build.success!
+ new_pipeline = create_pipeline(project, sha, branch)
+ new_pipeline.success!
end
it 'does not take outdated pipeline into account' do
@@ -87,7 +86,7 @@ describe Gitlab::Badge::Build::Status do
end
end
- def create_build(project, sha, branch)
+ def create_pipeline(project, sha, branch)
pipeline = create(:ci_empty_pipeline,
project: project,
sha: sha,
diff --git a/spec/lib/gitlab/badge/build/template_spec.rb b/spec/lib/gitlab/badge/pipeline/template_spec.rb
index a7e21fb8bb1..20fa4f879c3 100644
--- a/spec/lib/gitlab/badge/build/template_spec.rb
+++ b/spec/lib/gitlab/badge/pipeline/template_spec.rb
@@ -1,28 +1,28 @@
require 'spec_helper'
-describe Gitlab::Badge::Build::Template do
- let(:badge) { double(entity: 'build', status: 'success') }
+describe Gitlab::Badge::Pipeline::Template do
+ let(:badge) { double(entity: 'pipeline', status: 'success') }
let(:template) { described_class.new(badge) }
describe '#key_text' do
- it 'is always says build' do
- expect(template.key_text).to eq 'build'
+ it 'is always says pipeline' do
+ expect(template.key_text).to eq 'pipeline'
end
end
describe '#value_text' do
it 'is status value' do
- expect(template.value_text).to eq 'success'
+ expect(template.value_text).to eq 'passed'
end
end
describe 'widths and text anchors' do
it 'has fixed width and text anchors' do
- expect(template.width).to eq 92
- expect(template.key_width).to eq 38
+ expect(template.width).to eq 116
+ expect(template.key_width).to eq 62
expect(template.value_width).to eq 54
- expect(template.key_text_anchor).to eq 19
- expect(template.value_text_anchor).to eq 65
+ expect(template.key_text_anchor).to eq 31
+ expect(template.value_text_anchor).to eq 89
end
end
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index d8beb05601c..df66a031fec 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::Importer, lib: true do
+describe Gitlab::BitbucketImport::Importer do
include ImportSpecHelper
before do
@@ -58,7 +58,7 @@ describe Gitlab::BitbucketImport::Importer, lib: true do
)
end
- let(:importer) { Gitlab::BitbucketImport::Importer.new(project) }
+ let(:importer) { described_class.new(project) }
let(:issues_statuses_sample_data) do
{
diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
index 773d0d4d288..d7f7b26740d 100644
--- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::ProjectCreator, lib: true do
+describe Gitlab::BitbucketImport::ProjectCreator do
let(:user) { create(:user) }
let(:repo) do
@@ -27,7 +27,7 @@ describe Gitlab::BitbucketImport::ProjectCreator, lib: true do
it 'creates project' do
allow_any_instance_of(Project).to receive(:add_import_job)
- project_creator = Gitlab::BitbucketImport::ProjectCreator.new(repo, 'vim', namespace, user, access_params)
+ project_creator = described_class.new(repo, 'vim', namespace, user, access_params)
project = project_creator.execute
expect(project.import_url).to eq("ssh://git@bitbucket.org/asd/vim.git")
diff --git a/spec/lib/gitlab/blame_spec.rb b/spec/lib/gitlab/blame_spec.rb
index 26b1baf75be..7cab04e9fc9 100644
--- a/spec/lib/gitlab/blame_spec.rb
+++ b/spec/lib/gitlab/blame_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Blame, lib: true do
+describe Gitlab::Blame do
let(:project) { create(:project, :repository) }
let(:path) { 'files/ruby/popen.rb' }
let(:commit) { project.commit('master') }
diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
index 07db6c3a640..0daf41a7c86 100644
--- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
+++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
+describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do
let!(:project) { create(:project) }
let(:pipeline_status) { described_class.new(project) }
let(:cache_key) { "projects/#{project.id}/pipeline_status" }
@@ -28,8 +28,8 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
expect(project.instance_variable_get('@pipeline_status')).to be_a(described_class)
end
- describe 'without a status in redis' do
- it 'loads the status from a commit when it was not in redis' do
+ describe 'without a status in redis_cache' do
+ it 'loads the status from a commit when it was not in redis_cache' do
empty_status = { sha: nil, status: nil, ref: nil }
fake_pipeline = described_class.new(
project_without_status,
@@ -48,9 +48,9 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
described_class.load_in_batch_for_projects([project_without_status])
end
- it 'only connects to redis twice' do
+ it 'only connects to redis_cache twice' do
# Once to load, once to store in the cache
- expect(Gitlab::Redis).to receive(:with).exactly(2).and_call_original
+ expect(Gitlab::Redis::Cache).to receive(:with).exactly(2).and_call_original
described_class.load_in_batch_for_projects([project_without_status])
@@ -58,9 +58,9 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
end
end
- describe 'when a status was cached in redis' do
+ describe 'when a status was cached in redis_cache' do
before do
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::Cache.with do |redis|
redis.mapped_hmset(cache_key,
{ sha: sha, status: status, ref: ref })
end
@@ -76,8 +76,8 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
expect(pipeline_status.ref).to eq(ref)
end
- it 'only connects to redis once' do
- expect(Gitlab::Redis).to receive(:with).exactly(1).and_call_original
+ it 'only connects to redis_cache once' do
+ expect(Gitlab::Redis::Cache).to receive(:with).exactly(1).and_call_original
described_class.load_in_batch_for_projects([project])
@@ -94,8 +94,8 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
end
describe '.cached_results_for_projects' do
- it 'loads a status from redis for all projects' do
- Gitlab::Redis.with do |redis|
+ it 'loads a status from caching for all projects' do
+ Gitlab::Redis::Cache.with do |redis|
redis.mapped_hmset(cache_key, { sha: sha, status: status, ref: ref })
end
@@ -183,7 +183,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
end
end
- describe "#load_from_project" do
+ describe "#load_from_project", :clean_gitlab_redis_cache do
let!(:pipeline) { create(:ci_pipeline, :success, project: project, sha: project.commit.sha) }
it 'reads the status from the pipeline for the commit' do
@@ -203,40 +203,40 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
end
end
- describe "#store_in_cache", :redis do
- it "sets the object in redis" do
+ describe "#store_in_cache", :clean_gitlab_redis_cache do
+ it "sets the object in caching" do
pipeline_status.sha = '123456'
pipeline_status.status = 'failed'
pipeline_status.store_in_cache
- read_sha, read_status = Gitlab::Redis.with { |redis| redis.hmget(cache_key, :sha, :status) }
+ read_sha, read_status = Gitlab::Redis::Cache.with { |redis| redis.hmget(cache_key, :sha, :status) }
expect(read_sha).to eq('123456')
expect(read_status).to eq('failed')
end
end
- describe '#store_in_cache_if_needed', :redis do
+ describe '#store_in_cache_if_needed', :clean_gitlab_redis_cache do
it 'stores the state in the cache when the sha is the HEAD of the project' do
create(:ci_pipeline, :success, project: project, sha: project.commit.sha)
pipeline_status = described_class.load_for_project(project)
pipeline_status.store_in_cache_if_needed
- sha, status, ref = Gitlab::Redis.with { |redis| redis.hmget(cache_key, :sha, :status, :ref) }
+ sha, status, ref = Gitlab::Redis::Cache.with { |redis| redis.hmget(cache_key, :sha, :status, :ref) }
expect(sha).not_to be_nil
expect(status).not_to be_nil
expect(ref).not_to be_nil
end
- it "doesn't store the status in redis when the sha is not the head of the project" do
+ it "doesn't store the status in redis_cache when the sha is not the head of the project" do
other_status = described_class.new(
project,
pipeline_info: { sha: "123456", status: "failed" }
)
other_status.store_in_cache_if_needed
- sha, status = Gitlab::Redis.with { |redis| redis.hmget(cache_key, :sha, :status) }
+ sha, status = Gitlab::Redis::Cache.with { |redis| redis.hmget(cache_key, :sha, :status) }
expect(sha).to be_nil
expect(status).to be_nil
@@ -244,7 +244,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
it "deletes the cache if the repository doesn't have a head commit" do
empty_project = create(:empty_project)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::Cache.with do |redis|
redis.mapped_hmset(cache_key,
{ sha: 'sha', status: 'pending', ref: 'master' })
end
@@ -255,7 +255,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
})
other_status.store_in_cache_if_needed
- sha, status, ref = Gitlab::Redis.with { |redis| redis.hmget("projects/#{empty_project.id}/pipeline_status", :sha, :status, :ref) }
+ sha, status, ref = Gitlab::Redis::Cache.with { |redis| redis.hmget("projects/#{empty_project.id}/pipeline_status", :sha, :status, :ref) }
expect(sha).to be_nil
expect(status).to be_nil
@@ -263,20 +263,20 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
end
end
- describe "with a status in redis", :redis do
+ describe "with a status in caching", :clean_gitlab_redis_cache do
let(:status) { 'success' }
let(:sha) { '424d1b73bc0d3cb726eb7dc4ce17a4d48552f8c6' }
let(:ref) { 'master' }
before do
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::Cache.with do |redis|
redis.mapped_hmset(cache_key,
{ sha: sha, status: status, ref: ref })
end
end
describe '#load_from_cache' do
- it 'reads the status from redis' do
+ it 'reads the status from redis_cache' do
pipeline_status.load_from_cache
expect(pipeline_status.sha).to eq(sha)
@@ -292,10 +292,10 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :redis do
end
describe '#delete_from_cache' do
- it 'deletes values from redis' do
+ it 'deletes values from redis_cache' do
pipeline_status.delete_from_cache
- key_exists = Gitlab::Redis.with { |redis| redis.exists(cache_key) }
+ key_exists = Gitlab::Redis::Cache.with { |redis| redis.exists(cache_key) }
expect(key_exists).to be_falsy
end
diff --git a/spec/lib/gitlab/cache/request_cache_spec.rb b/spec/lib/gitlab/cache/request_cache_spec.rb
new file mode 100644
index 00000000000..5b82c216a13
--- /dev/null
+++ b/spec/lib/gitlab/cache/request_cache_spec.rb
@@ -0,0 +1,133 @@
+require 'spec_helper'
+
+describe Gitlab::Cache::RequestCache do
+ let(:klass) do
+ Class.new do
+ extend Gitlab::Cache::RequestCache
+
+ attr_accessor :id, :name, :result, :extra
+
+ def self.name
+ 'ExpensiveAlgorithm'
+ end
+
+ def initialize(id, name, result, extra = nil)
+ self.id = id
+ self.name = name
+ self.result = result
+ self.extra = nil
+ end
+
+ request_cache def compute(arg)
+ result << arg
+ end
+
+ request_cache def repute(arg)
+ result << arg
+ end
+
+ def dispute(arg)
+ result << arg
+ end
+ request_cache(:dispute) { extra }
+ end
+ end
+
+ let(:algorithm) { klass.new('id', 'name', []) }
+
+ shared_examples 'cache for the same instance' do
+ it 'does not compute twice for the same argument' do
+ algorithm.compute(true)
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true])
+ end
+
+ it 'computes twice for the different argument' do
+ algorithm.compute(true)
+ result = algorithm.compute(false)
+
+ expect(result).to eq([true, false])
+ end
+
+ it 'computes twice for the different class name' do
+ algorithm.compute(true)
+ allow(klass).to receive(:name).and_return('CheapAlgo')
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ it 'computes twice for the different method' do
+ algorithm.compute(true)
+ result = algorithm.repute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ context 'when request_cache_key is provided' do
+ before do
+ klass.request_cache_key do
+ [id, name]
+ end
+ end
+
+ it 'computes twice for the different keys, id' do
+ algorithm.compute(true)
+ algorithm.id = 'ad'
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ it 'computes twice for the different keys, name' do
+ algorithm.compute(true)
+ algorithm.name = 'same'
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+
+ it 'uses extra method cache key if provided' do
+ algorithm.dispute(true) # miss
+ algorithm.extra = true
+ algorithm.dispute(true) # miss
+ result = algorithm.dispute(true) # hit
+
+ expect(result).to eq([true, true])
+ end
+ end
+ end
+
+ context 'when RequestStore is active', :request_store do
+ it_behaves_like 'cache for the same instance'
+
+ it 'computes once for different instances when keys are the same' do
+ algorithm.compute(true)
+ result = klass.new('id', 'name', algorithm.result).compute(true)
+
+ expect(result).to eq([true])
+ end
+
+ it 'computes twice if RequestStore starts over' do
+ algorithm.compute(true)
+ RequestStore.end!
+ RequestStore.clear!
+ RequestStore.begin!
+ result = algorithm.compute(true)
+
+ expect(result).to eq([true, true])
+ end
+ end
+
+ context 'when RequestStore is inactive' do
+ it_behaves_like 'cache for the same instance'
+
+ it 'computes twice for different instances even if keys are the same' do
+ algorithm.compute(true)
+ result = klass.new('id', 'name', algorithm.result).compute(true)
+
+ expect(result).to eq([true, true])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/chat_name_token_spec.rb b/spec/lib/gitlab/chat_name_token_spec.rb
index 8c1e6efa9db..1e9fb9077fc 100644
--- a/spec/lib/gitlab/chat_name_token_spec.rb
+++ b/spec/lib/gitlab/chat_name_token_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatNameToken, lib: true do
+describe Gitlab::ChatNameToken do
context 'when using unknown token' do
let(:token) { }
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index 643e590438a..6c25b7349e1 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Checks::ChangeAccess, lib: true do
+describe Gitlab::Checks::ChangeAccess do
describe '#exec' do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb
index bc66ce83d4a..6c4cfa1203e 100644
--- a/spec/lib/gitlab/checks/force_push_spec.rb
+++ b/spec/lib/gitlab/checks/force_push_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Checks::ForcePush, lib: true do
+describe Gitlab::Checks::ForcePush do
let(:project) { create(:project, :repository) }
context "exit code checking" do
diff --git a/spec/lib/gitlab/ci/build/step_spec.rb b/spec/lib/gitlab/ci/build/step_spec.rb
index 49457b129e3..5a21282712a 100644
--- a/spec/lib/gitlab/ci/build/step_spec.rb
+++ b/spec/lib/gitlab/ci/build/step_spec.rb
@@ -1,21 +1,50 @@
require 'spec_helper'
describe Gitlab::Ci::Build::Step do
- let(:job) { create(:ci_build, :no_options, commands: "ls -la\ndate") }
-
describe '#from_commands' do
- subject { described_class.from_commands(job) }
-
- it 'fabricates an object' do
- expect(subject.name).to eq(:script)
- expect(subject.script).to eq(['ls -la', 'date'])
- expect(subject.timeout).to eq(job.timeout)
- expect(subject.when).to eq('on_success')
- expect(subject.allow_failure).to be_falsey
+ shared_examples 'has correct script' do
+ subject { described_class.from_commands(job) }
+
+ it 'fabricates an object' do
+ expect(subject.name).to eq(:script)
+ expect(subject.script).to eq(script)
+ expect(subject.timeout).to eq(job.timeout)
+ expect(subject.when).to eq('on_success')
+ expect(subject.allow_failure).to be_falsey
+ end
+ end
+
+ context 'when commands are specified' do
+ it_behaves_like 'has correct script' do
+ let(:job) { create(:ci_build, :no_options, commands: "ls -la\ndate") }
+ let(:script) { ['ls -la', 'date'] }
+ end
+ end
+
+ context 'when script option is specified' do
+ it_behaves_like 'has correct script' do
+ let(:job) { create(:ci_build, :no_options, options: { script: ["ls -la\necho aaa", "date"] }) }
+ let(:script) { ["ls -la\necho aaa", 'date'] }
+ end
+ end
+
+ context 'when before and script option is specified' do
+ it_behaves_like 'has correct script' do
+ let(:job) do
+ create(:ci_build, options: {
+ before_script: ["ls -la\necho aaa"],
+ script: ["date"]
+ })
+ end
+
+ let(:script) { ["ls -la\necho aaa", 'date'] }
+ end
end
end
describe '#from_after_script' do
+ let(:job) { create(:ci_build) }
+
subject { described_class.from_after_script(job) }
context 'when after_script is empty' do
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index 878b1d6b862..8f711e02f9b 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Cache do
- let(:entry) { described_class.new(config) }
+ subject(:entry) { described_class.new(config) }
describe 'validations' do
before do
@@ -9,22 +9,44 @@ describe Gitlab::Ci::Config::Entry::Cache do
end
context 'when entry config value is correct' do
+ let(:policy) { nil }
+
let(:config) do
{ key: 'some key',
untracked: true,
- paths: ['some/path/'] }
+ paths: ['some/path/'],
+ policy: policy }
end
describe '#value' do
it 'returns hash value' do
- expect(entry.value).to eq config
+ expect(entry.value).to eq(key: 'some key', untracked: true, paths: ['some/path/'], policy: 'pull-push')
end
end
describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
+ it { is_expected.to be_valid }
+ end
+
+ context 'policy is pull-push' do
+ let(:policy) { 'pull-push' }
+
+ it { is_expected.to be_valid }
+ it { expect(entry.value).to include(policy: 'pull-push') }
+ end
+
+ context 'policy is push' do
+ let(:policy) { 'push' }
+
+ it { is_expected.to be_valid }
+ it { expect(entry.value).to include(policy: 'push') }
+ end
+
+ context 'policy is pull' do
+ let(:policy) { 'pull' }
+
+ it { is_expected.to be_valid }
+ it { expect(entry.value).to include(policy: 'pull') }
end
context 'when key is missing' do
@@ -44,12 +66,20 @@ describe Gitlab::Ci::Config::Entry::Cache do
context 'when entry value is not correct' do
describe '#errors' do
+ subject { entry.errors }
context 'when is not a hash' do
let(:config) { 'ls' }
it 'reports errors with config value' do
- expect(entry.errors)
- .to include 'cache config should be a hash'
+ is_expected.to include 'cache config should be a hash'
+ end
+ end
+
+ context 'when policy is unknown' do
+ let(:config) { { policy: "unknown" } }
+
+ it 'reports error' do
+ is_expected.to include('cache policy should be pull-push, push, or pull')
end
end
@@ -57,8 +87,7 @@ describe Gitlab::Ci::Config::Entry::Cache do
let(:config) { { key: 1 } }
it 'reports error with descendants' do
- expect(entry.errors)
- .to include 'key config should be a string or symbol'
+ is_expected.to include 'key config should be a string or symbol'
end
end
@@ -66,8 +95,7 @@ describe Gitlab::Ci::Config::Entry::Cache do
let(:config) { { invalid: true } }
it 'reports error with descendants' do
- expect(entry.errors)
- .to include 'cache config contains unknown keys: invalid'
+ is_expected.to include 'cache config contains unknown keys: invalid'
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index 293f112b2b0..1860ed79bfd 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -143,7 +143,7 @@ describe Gitlab::Ci::Config::Entry::Global do
describe '#cache_value' do
it 'returns cache configuration' do
expect(global.cache_value)
- .to eq(key: 'k', untracked: true, paths: ['public/'])
+ .to eq(key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push')
end
end
@@ -157,7 +157,7 @@ describe Gitlab::Ci::Config::Entry::Global do
image: { name: 'ruby:2.2' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
- cache: { key: 'k', untracked: true, paths: ['public/'] },
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
variables: { 'VAR' => 'value' },
ignore: false,
after_script: ['make clean'] },
@@ -168,7 +168,7 @@ describe Gitlab::Ci::Config::Entry::Global do
image: { name: 'ruby:2.2' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
- cache: { key: 'k', untracked: true, paths: ['public/'] },
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
variables: {},
ignore: false,
after_script: ['make clean'] }
@@ -212,7 +212,7 @@ describe Gitlab::Ci::Config::Entry::Global do
describe '#cache_value' do
it 'returns correct cache definition' do
- expect(global.cache_value).to eq(key: 'a')
+ expect(global.cache_value).to eq(key: 'a', policy: 'pull-push')
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index bca22e39500..1a4d9ed5517 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -38,7 +38,7 @@ describe Gitlab::Ci::Config::Entry::Image do
end
context 'when configuration is a hash' do
- let(:config) { { name: 'ruby:2.2', entrypoint: '/bin/sh' } }
+ let(:config) { { name: 'ruby:2.2', entrypoint: %w(/bin/sh run) } }
describe '#value' do
it 'returns image hash' do
@@ -66,7 +66,7 @@ describe Gitlab::Ci::Config::Entry::Image do
describe '#entrypoint' do
it "returns image's entrypoint" do
- expect(entry.entrypoint).to eq '/bin/sh'
+ expect(entry.entrypoint).to eq %w(/bin/sh run)
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 92cba689f47..6769f64f950 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -80,6 +80,45 @@ describe Gitlab::Ci::Config::Entry::Job do
expect(entry.errors).to include "job script can't be blank"
end
end
+
+ context 'when retry value is not correct' do
+ context 'when it is not a numeric value' do
+ let(:config) { { retry: true } }
+
+ it 'returns error about invalid type' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'job retry is not a number'
+ end
+ end
+
+ context 'when it is lower than zero' do
+ let(:config) { { retry: -1 } }
+
+ it 'returns error about value too low' do
+ expect(entry).not_to be_valid
+ expect(entry.errors)
+ .to include 'job retry must be greater than or equal to 0'
+ end
+ end
+
+ context 'when it is not an integer' do
+ let(:config) { { retry: 1.5 } }
+
+ it 'returns error about wrong value' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'job retry must be an integer'
+ end
+ end
+
+ context 'when the value is too high' do
+ let(:config) { { retry: 10 } }
+
+ it 'returns error about value too high' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'job retry must be less than or equal to 2'
+ end
+ end
+ end
end
end
@@ -109,7 +148,7 @@ describe Gitlab::Ci::Config::Entry::Job do
it 'overrides global config' do
expect(entry[:image].value).to eq(name: 'some_image')
- expect(entry[:cache].value).to eq(key: 'test')
+ expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push')
end
end
@@ -123,7 +162,7 @@ describe Gitlab::Ci::Config::Entry::Job do
it 'uses config from global entry' do
expect(entry[:image].value).to eq 'specified'
- expect(entry[:cache].value).to eq(key: 'test')
+ expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push')
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
index 7202fe525e4..9ebf947a751 100644
--- a/spec/lib/gitlab/ci/config/entry/service_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -43,7 +43,7 @@ describe Gitlab::Ci::Config::Entry::Service do
context 'when configuration is a hash' do
let(:config) do
- { name: 'postgresql:9.5', alias: 'db', command: 'cmd', entrypoint: '/bin/sh' }
+ { name: 'postgresql:9.5', alias: 'db', command: %w(cmd run), entrypoint: %w(/bin/sh run) }
end
describe '#valid?' do
@@ -72,13 +72,13 @@ describe Gitlab::Ci::Config::Entry::Service do
describe '#command' do
it "returns service's command" do
- expect(entry.command).to eq 'cmd'
+ expect(entry.command).to eq %w(cmd run)
end
end
describe '#entrypoint' do
it "returns service's entrypoint" do
- expect(entry.entrypoint).to eq '/bin/sh'
+ expect(entry.entrypoint).to eq %w(/bin/sh run)
end
end
end
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
index 114d2490490..5a7a42d84c0 100644
--- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -48,7 +48,9 @@ describe Gitlab::Ci::Status::Build::Cancelable do
describe '#has_action?' do
context 'when user is allowed to update build' do
before do
- build.project.team << [user, :developer]
+ stub_not_protect_default_branch
+
+ build.project.add_developer(user)
end
it { is_expected.to have_action }
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index c8a97016f20..8768302eda1 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -7,7 +7,9 @@ describe Gitlab::Ci::Status::Build::Factory do
let(:factory) { described_class.new(build, user) }
before do
- project.team << [user, :developer]
+ stub_not_protect_default_branch
+
+ project.add_developer(user)
end
context 'when build is successful' do
@@ -225,19 +227,19 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when user has ability to play action' do
- before do
- project.add_developer(user)
-
- create(:protected_branch, :developers_can_merge,
- name: build.ref, project: project)
- end
-
it 'fabricates status that has action' do
expect(status).to have_action
end
end
context 'when user does not have ability to play action' do
+ before do
+ allow(build.project).to receive(:empty_repo?).and_return(false)
+
+ create(:protected_branch, :no_one_can_push,
+ name: build.ref, project: build.project)
+ end
+
it 'fabricates status that has no action' do
expect(status).not_to have_action
end
@@ -262,6 +264,13 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when user is not allowed to execute manual action' do
+ before do
+ allow(build.project).to receive(:empty_repo?).and_return(false)
+
+ create(:protected_branch, :no_one_can_push,
+ name: build.ref, project: build.project)
+ end
+
it 'fabricates status with correct details' do
expect(status.text).to eq 'manual'
expect(status.group).to eq 'manual'
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
index 099d873fc01..21026f2c968 100644
--- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -48,7 +48,9 @@ describe Gitlab::Ci::Status::Build::Retryable do
describe '#has_action?' do
context 'when user is allowed to update build' do
before do
- build.project.team << [user, :developer]
+ stub_not_protect_default_branch
+
+ build.project.add_developer(user)
end
it { is_expected.to have_action }
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
index 23902f26b1a..e0425103f41 100644
--- a/spec/lib/gitlab/ci/status/build/stop_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -20,7 +20,9 @@ describe Gitlab::Ci::Status::Build::Stop do
describe '#has_action?' do
context 'when user is allowed to update build' do
before do
- build.project.team << [user, :developer]
+ stub_not_protect_default_branch
+
+ build.project.add_developer(user)
end
it { is_expected.to have_action }
diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb
index bbb3f9912a3..ebe5af56160 100644
--- a/spec/lib/gitlab/ci/trace/stream_spec.rb
+++ b/spec/lib/gitlab/ci/trace/stream_spec.rb
@@ -293,5 +293,55 @@ describe Gitlab::Ci::Trace::Stream do
it { is_expected.to eq("65") }
end
+
+ context 'malicious regexp' do
+ let(:data) { malicious_text }
+ let(:regex) { malicious_regexp }
+
+ include_examples 'malicious regexp'
+ end
+
+ context 'multi-line data with rooted regexp' do
+ let(:data) { "\n65%\n" }
+ let(:regex) { '^(\d+)\%$' }
+
+ it { is_expected.to eq('65') }
+ end
+
+ context 'long line' do
+ let(:data) { 'a' * 80000 + '100%' + 'a' * 80000 }
+ let(:regex) { '\d+\%' }
+
+ it { is_expected.to eq('100') }
+ end
+
+ context 'many lines' do
+ let(:data) { "foo\n" * 80000 + "100%\n" + "foo\n" * 80000 }
+ let(:regex) { '\d+\%' }
+
+ it { is_expected.to eq('100') }
+ end
+
+ context 'empty regex' do
+ let(:data) { 'foo' }
+ let(:regex) { '' }
+
+ it 'skips processing' do
+ expect(stream).not_to receive(:read)
+
+ is_expected.to be_nil
+ end
+ end
+
+ context 'nil regex' do
+ let(:data) { 'foo' }
+ let(:regex) { nil }
+
+ it 'skips processing' do
+ expect(stream).not_to receive(:read)
+
+ is_expected.to be_nil
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci_access_spec.rb b/spec/lib/gitlab/ci_access_spec.rb
index eaf8f1d0f1c..75b90e76083 100644
--- a/spec/lib/gitlab/ci_access_spec.rb
+++ b/spec/lib/gitlab/ci_access_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::CiAccess, lib: true do
- let(:access) { Gitlab::CiAccess.new }
+describe Gitlab::CiAccess do
+ let(:access) { described_class.new }
describe '#can_do_action?' do
context 'when action is :build_download_code' do
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index ca68010cb89..8ff6125ada1 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ClosingIssueExtractor, lib: true do
+describe Gitlab::ClosingIssueExtractor do
let(:project) { create(:empty_project) }
let(:project2) { create(:empty_project) }
let(:forked_project) { Projects::ForkService.new(project, project.creator).execute }
@@ -276,7 +276,7 @@ describe Gitlab::ClosingIssueExtractor, lib: true do
context "with a cross-project URL" do
it do
- message = "Closes #{urls.namespace_project_issue_url(issue2.project.namespace, issue2.project, issue2)}"
+ message = "Closes #{urls.project_issue_url(issue2.project, issue2)}"
expect(subject.closed_by_message(message)).to eq([issue2])
end
end
@@ -292,7 +292,7 @@ describe Gitlab::ClosingIssueExtractor, lib: true do
context "with an invalid URL" do
it do
- message = "Closes https://google.com#{urls.namespace_project_issue_path(issue2.project.namespace, issue2.project, issue2)}"
+ message = "Closes https://google.com#{urls.project_issue_path(issue2.project, issue2)}"
expect(subject.closed_by_message(message)).to eq([])
end
end
@@ -347,14 +347,14 @@ describe Gitlab::ClosingIssueExtractor, lib: true do
end
it "fetches cross-project URL references" do
- message = "Closes #{urls.namespace_project_issue_url(issue2.project.namespace, issue2.project, issue2)} and #{reference}"
+ message = "Closes #{urls.project_issue_url(issue2.project, issue2)} and #{reference}"
expect(subject.closed_by_message(message))
.to match_array([issue, issue2])
end
it "ignores invalid cross-project URL references" do
- message = "Closes https://google.com#{urls.namespace_project_issue_path(issue2.project.namespace, issue2.project, issue2)} and #{reference}"
+ message = "Closes https://google.com#{urls.project_issue_path(issue2.project, issue2)} and #{reference}"
expect(subject.closed_by_message(message))
.to match_array([issue])
diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb
index 0a1ec66f199..c7be45dbcd3 100644
--- a/spec/lib/gitlab/color_schemes_spec.rb
+++ b/spec/lib/gitlab/color_schemes_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ColorSchemes, lib: true do
+describe Gitlab::ColorSchemes do
describe '.body_classes' do
it 'returns a space-separated list of class names' do
css = described_class.body_classes
diff --git a/spec/lib/gitlab/conflict/file_collection_spec.rb b/spec/lib/gitlab/conflict/file_collection_spec.rb
index 27f23ea70dc..a4d7628b03a 100644
--- a/spec/lib/gitlab/conflict/file_collection_spec.rb
+++ b/spec/lib/gitlab/conflict/file_collection_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Conflict::FileCollection, lib: true do
+describe Gitlab::Conflict::FileCollection do
let(:merge_request) { create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start') }
let(:file_collection) { described_class.read_only(merge_request) }
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 585eeb77bd5..5356e9742b4 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Conflict::File, lib: true do
+describe Gitlab::Conflict::File do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:rugged) { repository.rugged }
@@ -10,7 +10,7 @@ describe Gitlab::Conflict::File, lib: true do
let(:index) { rugged.merge_commits(our_commit, their_commit) }
let(:conflict) { index.conflicts.last }
let(:merge_file_result) { index.merge_file('files/ruby/regex.rb') }
- let(:conflict_file) { Gitlab::Conflict::File.new(merge_file_result, conflict, merge_request: merge_request) }
+ let(:conflict_file) { described_class.new(merge_file_result, conflict, merge_request: merge_request) }
describe '#resolve_lines' do
let(:section_keys) { conflict_file.sections.map { |section| section[:id] }.compact }
@@ -220,7 +220,7 @@ end
FILE
end
- let(:conflict_file) { Gitlab::Conflict::File.new({ data: file }, conflict, merge_request: merge_request) }
+ let(:conflict_file) { described_class.new({ data: file }, conflict, merge_request: merge_request) }
let(:sections) { conflict_file.sections }
it 'sets the correct match line headers' do
diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb
index aed57b75789..fce606a2bb5 100644
--- a/spec/lib/gitlab/conflict/parser_spec.rb
+++ b/spec/lib/gitlab/conflict/parser_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::Conflict::Parser, lib: true do
- let(:parser) { Gitlab::Conflict::Parser.new }
+describe Gitlab::Conflict::Parser do
+ let(:parser) { described_class.new }
describe '#parse' do
def parse_text(text)
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index a566f24f6a6..d57ffcae8e1 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -27,10 +27,23 @@ describe Gitlab::CurrentSettings do
end
it 'falls back to DB if Redis fails' do
+ db_settings = ApplicationSetting.create!(ApplicationSetting.defaults)
+
expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError)
- expect(ApplicationSetting).to receive(:last).and_call_original
+ expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(Redis::BaseError)
- expect(current_application_settings).to be_a(ApplicationSetting)
+ expect(current_application_settings).to eq(db_settings)
+ end
+
+ it 'creates default ApplicationSettings if none are present' do
+ expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError)
+ expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(Redis::BaseError)
+
+ settings = current_application_settings
+
+ expect(settings).to be_a(ApplicationSetting)
+ expect(settings).to be_persisted
+ expect(settings).to have_attributes(ApplicationSetting.defaults)
end
context 'with migrations pending' do
diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
index 3dd76ba5b8a..592448aef96 100644
--- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::CycleAnalytics::StageSummary, models: true do
+describe Gitlab::CycleAnalytics::StageSummary do
let(:project) { create(:project, :repository) }
let(:from) { 1.day.ago }
let(:user) { create(:user, :admin) }
diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb
index 04ec34492e1..6415e4083d6 100644
--- a/spec/lib/gitlab/data_builder/note_spec.rb
+++ b/spec/lib/gitlab/data_builder/note_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::DataBuilder::Note, lib: true do
+describe Gitlab::DataBuilder::Note do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:data) { described_class.build(note, user) }
diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb
index 73936969832..cb430b47463 100644
--- a/spec/lib/gitlab/data_builder/push_spec.rb
+++ b/spec/lib/gitlab/data_builder/push_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::DataBuilder::Push, lib: true do
+describe Gitlab::DataBuilder::Push do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/data_builder/wiki_page_spec.rb b/spec/lib/gitlab/data_builder/wiki_page_spec.rb
new file mode 100644
index 00000000000..a776d888c47
--- /dev/null
+++ b/spec/lib/gitlab/data_builder/wiki_page_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::DataBuilder::WikiPage do
+ let(:project) { create(:project, :repository) }
+ let(:wiki_page) { create(:wiki_page, wiki: project.wiki) }
+ let(:user) { create(:user) }
+
+ describe '.build' do
+ let(:data) { described_class.build(wiki_page, user, 'create') }
+
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:object_kind]).to eq('wiki_page') }
+ it { expect(data[:user]).to eq(user.hook_attrs) }
+ it { expect(data[:project]).to eq(project.hook_attrs) }
+ it { expect(data[:wiki]).to eq(project.wiki.hook_attrs) }
+
+ it { expect(data[:object_attributes]).to include(wiki_page.hook_attrs) }
+ it { expect(data[:object_attributes]).to include(url: Gitlab::UrlBuilder.build(wiki_page)) }
+ it { expect(data[:object_attributes]).to include(action: 'create') }
+ end
+end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 6a0485112c1..d3dbd82e8ba 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::Database::MigrationHelpers, lib: true do
+describe Gitlab::Database::MigrationHelpers do
let(:model) do
ActiveRecord::Migration.new.extend(
- Gitlab::Database::MigrationHelpers
+ described_class
)
end
@@ -174,13 +174,23 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
allow(Gitlab::Database).to receive(:mysql?).and_return(false)
end
- it 'creates a concurrent foreign key' do
+ it 'creates a concurrent foreign key and validates it' do
expect(model).to receive(:disable_statement_timeout)
expect(model).to receive(:execute).ordered.with(/NOT VALID/)
expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
end
+
+ it 'appends a valid ON DELETE statement' do
+ expect(model).to receive(:disable_statement_timeout)
+ expect(model).to receive(:execute).with(/ON DELETE SET NULL/)
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+
+ model.add_concurrent_foreign_key(:projects, :users,
+ column: :user_id,
+ on_delete: :nullify)
+ end
end
end
end
@@ -262,39 +272,53 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
end
describe '#update_column_in_batches' do
- before do
- create_list(:empty_project, 5)
- end
+ context 'when running outside of a transaction' do
+ before do
+ expect(model).to receive(:transaction_open?).and_return(false)
- it 'updates all the rows in a table' do
- model.update_column_in_batches(:projects, :import_error, 'foo')
+ create_list(:empty_project, 5)
+ end
- expect(Project.where(import_error: 'foo').count).to eq(5)
- end
+ it 'updates all the rows in a table' do
+ model.update_column_in_batches(:projects, :import_error, 'foo')
- it 'updates boolean values correctly' do
- model.update_column_in_batches(:projects, :archived, true)
+ expect(Project.where(import_error: 'foo').count).to eq(5)
+ end
- expect(Project.where(archived: true).count).to eq(5)
- end
+ it 'updates boolean values correctly' do
+ model.update_column_in_batches(:projects, :archived, true)
- context 'when a block is supplied' do
- it 'yields an Arel table and query object to the supplied block' do
- first_id = Project.first.id
+ expect(Project.where(archived: true).count).to eq(5)
+ end
- model.update_column_in_batches(:projects, :archived, true) do |t, query|
- query.where(t[:id].eq(first_id))
+ context 'when a block is supplied' do
+ it 'yields an Arel table and query object to the supplied block' do
+ first_id = Project.first.id
+
+ model.update_column_in_batches(:projects, :archived, true) do |t, query|
+ query.where(t[:id].eq(first_id))
+ end
+
+ expect(Project.where(archived: true).count).to eq(1)
end
+ end
- expect(Project.where(archived: true).count).to eq(1)
+ context 'when the value is Arel.sql (Arel::Nodes::SqlLiteral)' do
+ it 'updates the value as a SQL expression' do
+ model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
+
+ expect(Project.sum(:star_count)).to eq(2 * Project.count)
+ end
end
end
- context 'when the value is Arel.sql (Arel::Nodes::SqlLiteral)' do
- it 'updates the value as a SQL expression' do
- model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
+ context 'when running inside the transaction' do
+ it 'raises RuntimeError' do
+ expect(model).to receive(:transaction_open?).and_return(true)
- expect(Project.sum(:star_count)).to eq(2 * Project.count)
+ expect do
+ model.update_column_in_batches(:projects, :star_count, Arel.sql('1+1'))
+ end.to raise_error(RuntimeError)
end
end
end
@@ -303,7 +327,9 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
context 'outside of a transaction' do
context 'when a column limit is not set' do
before do
- expect(model).to receive(:transaction_open?).and_return(false)
+ expect(model).to receive(:transaction_open?)
+ .and_return(false)
+ .at_least(:once)
expect(model).to receive(:transaction).and_yield
@@ -810,7 +836,11 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
let!(:user) { create(:user, name: 'Kathy Alice Aliceson') }
it 'replaces the correct part of the string' do
- model.update_column_in_batches(:users, :name, model.replace_sql(Arel::Table.new(:users)[:name], 'Alice', 'Eve'))
+ allow(model).to receive(:transaction_open?).and_return(false)
+ query = model.replace_sql(Arel::Table.new(:users)[:name], 'Alice', 'Eve')
+
+ model.update_column_in_batches(:users, :name, query)
+
expect(user.reload.name).to eq('Kathy Eve Aliceson')
end
end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
index a3ab4e3dd9e..df7d1b5d27a 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
@@ -1,11 +1,12 @@
require 'spec_helper'
-describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase do
+describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :truncate do
let(:migration) { FakeRenameReservedPathMigrationV1.new }
let(:subject) { described_class.new(['the-path'], migration) }
before do
allow(migration).to receive(:say)
+ TestEnv.clean_test_path
end
def migration_namespace(namespace)
@@ -153,6 +154,30 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase do
end
end
+ describe '#perform_rename' do
+ describe 'for namespaces' do
+ let(:namespace) { create(:namespace, path: 'the-path') }
+ it 'renames the path' do
+ subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed')
+
+ expect(namespace.reload.path).to eq('renamed')
+ end
+
+ it 'renames all the routes for the namespace' do
+ child = create(:group, path: 'child', parent: namespace)
+ project = create(:project, namespace: child, path: 'the-project')
+ other_one = create(:namespace, path: 'the-path-is-similar')
+
+ subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed')
+
+ expect(namespace.reload.route.path).to eq('renamed')
+ expect(child.reload.route.path).to eq('renamed/child')
+ expect(project.reload.route.path).to eq('renamed/child/the-project')
+ expect(other_one.reload.route.path).to eq('the-path-is-similar')
+ end
+ end
+ end
+
describe '#move_pages' do
it 'moves the pages directory' do
expect(subject).to receive(:move_folders)
@@ -203,4 +228,53 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase do
expect(File.exist?(expected_file)).to be(true)
end
end
+
+ describe '#track_rename', redis: true do
+ it 'tracks a rename in redis' do
+ key = 'rename:FakeRenameReservedPathMigrationV1:namespace'
+
+ subject.track_rename('namespace', 'path/to/namespace', 'path/to/renamed')
+
+ old_path, new_path = [nil, nil]
+ Gitlab::Redis::SharedState.with do |redis|
+ rename_info = redis.lpop(key)
+ old_path, new_path = JSON.parse(rename_info)
+ end
+
+ expect(old_path).to eq('path/to/namespace')
+ expect(new_path).to eq('path/to/renamed')
+ end
+ end
+
+ describe '#reverts_for_type', redis: true do
+ it 'yields for each tracked rename' do
+ subject.track_rename('project', 'old_path', 'new_path')
+ subject.track_rename('project', 'old_path2', 'new_path2')
+ subject.track_rename('namespace', 'namespace_path', 'new_namespace_path')
+
+ expect { |b| subject.reverts_for_type('project', &b) }
+ .to yield_successive_args(%w(old_path2 new_path2), %w(old_path new_path))
+ expect { |b| subject.reverts_for_type('namespace', &b) }
+ .to yield_with_args('namespace_path', 'new_namespace_path')
+ end
+
+ it 'keeps the revert in redis if it failed' do
+ subject.track_rename('project', 'old_path', 'new_path')
+
+ subject.reverts_for_type('project') do
+ raise 'whatever happens, keep going!'
+ end
+
+ key = 'rename:FakeRenameReservedPathMigrationV1:project'
+ stored_renames = nil
+ rename_count = 0
+ Gitlab::Redis::SharedState.with do |redis|
+ stored_renames = redis.lrange(key, 0, 1)
+ rename_count = redis.llen(key)
+ end
+
+ expect(rename_count).to eq(1)
+ expect(JSON.parse(stored_renames.first)).to eq(%w(old_path new_path))
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
index aa63f6f9805..803e923b4a5 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
@@ -1,11 +1,13 @@
require 'spec_helper'
-describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
+describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, :truncate do
let(:migration) { FakeRenameReservedPathMigrationV1.new }
let(:subject) { described_class.new(['the-path'], migration) }
+ let(:namespace) { create(:group, name: 'the-path') }
before do
allow(migration).to receive(:say)
+ TestEnv.clean_test_path
end
def migration_namespace(namespace)
@@ -137,8 +139,6 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
end
describe "#rename_namespace" do
- let(:namespace) { create(:group, name: 'the-path') }
-
it 'renames paths & routes for the namespace' do
expect(subject).to receive(:rename_path_for_routable)
.with(namespace)
@@ -149,11 +149,27 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
expect(namespace.reload.path).to eq('the-path0')
end
+ it 'tracks the rename' do
+ expect(subject).to receive(:track_rename)
+ .with('namespace', 'the-path', 'the-path0')
+
+ subject.rename_namespace(namespace)
+ end
+
+ it 'renames things related to the namespace' do
+ expect(subject).to receive(:rename_namespace_dependencies)
+ .with(namespace, 'the-path', 'the-path0')
+
+ subject.rename_namespace(namespace)
+ end
+ end
+
+ describe '#rename_namespace_dependencies' do
it "moves the the repository for a project in the namespace" do
create(:project, namespace: namespace, path: "the-path-project")
expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git")
- subject.rename_namespace(namespace)
+ subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
expect(File.directory?(expected_repo)).to be(true)
end
@@ -161,13 +177,13 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
it "moves the uploads for the namespace" do
expect(subject).to receive(:move_uploads).with("the-path", "the-path0")
- subject.rename_namespace(namespace)
+ subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
end
it "moves the pages for the namespace" do
expect(subject).to receive(:move_pages).with("the-path", "the-path0")
- subject.rename_namespace(namespace)
+ subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
end
it 'invalidates the markdown cache of related projects' do
@@ -175,13 +191,13 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
expect(subject).to receive(:remove_cached_html_for_projects).with([project.id])
- subject.rename_namespace(namespace)
+ subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
end
it "doesn't rename users for other namespaces" do
expect(subject).not_to receive(:rename_user)
- subject.rename_namespace(namespace)
+ subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0')
end
it 'renames the username of a namespace for a user' do
@@ -189,7 +205,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
expect(subject).to receive(:rename_user).with('the-path', 'the-path0')
- subject.rename_namespace(user.namespace)
+ subject.rename_namespace_dependencies(user.namespace, 'the-path', 'the-path0')
end
end
@@ -224,4 +240,50 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
subject.rename_namespaces(type: :child)
end
end
+
+ describe '#revert_renames', redis: true do
+ it 'renames the routes back to the previous values' do
+ project = create(:project, path: 'a-project', namespace: namespace)
+ subject.rename_namespace(namespace)
+
+ expect(subject).to receive(:perform_rename)
+ .with(
+ kind_of(Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Namespace),
+ 'the-path0',
+ 'the-path'
+ ).and_call_original
+
+ subject.revert_renames
+
+ expect(namespace.reload.path).to eq('the-path')
+ expect(namespace.reload.route.path).to eq('the-path')
+ expect(project.reload.route.path).to eq('the-path/a-project')
+ end
+
+ it 'moves the repositories back to their original place' do
+ project = create(:project, path: 'a-project', namespace: namespace)
+ project.create_repository
+ subject.rename_namespace(namespace)
+
+ expected_path = File.join(TestEnv.repos_path, 'the-path', 'a-project.git')
+
+ expect(subject).to receive(:rename_namespace_dependencies)
+ .with(
+ kind_of(Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Namespace),
+ 'the-path0',
+ 'the-path'
+ ).and_call_original
+
+ subject.revert_renames
+
+ expect(File.directory?(expected_path)).to be_truthy
+ end
+
+ it "doesn't break when the namespace was renamed" do
+ subject.rename_namespace(namespace)
+ namespace.update_attributes!(path: 'renamed-afterwards')
+
+ expect { subject.revert_renames }.not_to raise_error
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
index 9a6ed98898d..0e240a5ccf1 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
@@ -1,11 +1,17 @@
require 'spec_helper'
-describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects do
+describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :truncate do
let(:migration) { FakeRenameReservedPathMigrationV1.new }
let(:subject) { described_class.new(['the-path'], migration) }
+ let(:project) do
+ create(:empty_project,
+ path: 'the-path',
+ namespace: create(:namespace, path: 'known-parent' ))
+ end
before do
allow(migration).to receive(:say)
+ TestEnv.clean_test_path
end
describe '#projects_for_paths' do
@@ -47,12 +53,6 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects do
end
describe '#rename_project' do
- let(:project) do
- create(:empty_project,
- path: 'the-path',
- namespace: create(:namespace, path: 'known-parent' ))
- end
-
it 'renames path & route for the project' do
expect(subject).to receive(:rename_path_for_routable)
.with(project)
@@ -63,27 +63,42 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects do
expect(project.reload.path).to eq('the-path0')
end
+ it 'tracks the rename' do
+ expect(subject).to receive(:track_rename)
+ .with('project', 'known-parent/the-path', 'known-parent/the-path0')
+
+ subject.rename_project(project)
+ end
+
+ it 'renames the folders for the project' do
+ expect(subject).to receive(:move_project_folders).with(project, 'known-parent/the-path', 'known-parent/the-path0')
+
+ subject.rename_project(project)
+ end
+ end
+
+ describe '#move_project_folders' do
it 'moves the wiki & the repo' do
expect(subject).to receive(:move_repository)
.with(project, 'known-parent/the-path.wiki', 'known-parent/the-path0.wiki')
expect(subject).to receive(:move_repository)
.with(project, 'known-parent/the-path', 'known-parent/the-path0')
- subject.rename_project(project)
+ subject.move_project_folders(project, 'known-parent/the-path', 'known-parent/the-path0')
end
it 'moves uploads' do
expect(subject).to receive(:move_uploads)
.with('known-parent/the-path', 'known-parent/the-path0')
- subject.rename_project(project)
+ subject.move_project_folders(project, 'known-parent/the-path', 'known-parent/the-path0')
end
it 'moves pages' do
expect(subject).to receive(:move_pages)
.with('known-parent/the-path', 'known-parent/the-path0')
- subject.rename_project(project)
+ subject.move_project_folders(project, 'known-parent/the-path', 'known-parent/the-path0')
end
end
@@ -99,4 +114,47 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects do
expect(File.directory?(expected_path)).to be(true)
end
end
+
+ describe '#revert_renames', redis: true do
+ it 'renames the routes back to the previous values' do
+ subject.rename_project(project)
+
+ expect(subject).to receive(:perform_rename)
+ .with(
+ kind_of(Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Project),
+ 'known-parent/the-path0',
+ 'known-parent/the-path'
+ ).and_call_original
+
+ subject.revert_renames
+
+ expect(project.reload.path).to eq('the-path')
+ expect(project.route.path).to eq('known-parent/the-path')
+ end
+
+ it 'moves the repositories back to their original place' do
+ project.create_repository
+ subject.rename_project(project)
+
+ expected_path = File.join(TestEnv.repos_path, 'known-parent', 'the-path.git')
+
+ expect(subject).to receive(:move_project_folders)
+ .with(
+ kind_of(Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Project),
+ 'known-parent/the-path0',
+ 'known-parent/the-path'
+ ).and_call_original
+
+ subject.revert_renames
+
+ expect(File.directory?(expected_path)).to be_truthy
+ end
+
+ it "doesn't break when the project was renamed" do
+ subject.rename_project(project)
+ project.update_attributes!(path: 'renamed-afterwards')
+
+ expect { subject.revert_renames }.not_to raise_error
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb
index bdd3af4ad44..7695b95dc57 100644
--- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb
@@ -13,7 +13,7 @@ shared_examples 'renames child namespaces' do |type|
end
end
-describe Gitlab::Database::RenameReservedPathsMigration::V1 do
+describe Gitlab::Database::RenameReservedPathsMigration::V1, :truncate do
let(:subject) { FakeRenameReservedPathMigrationV1.new }
before do
@@ -51,4 +51,26 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1 do
subject.rename_root_paths('the-path')
end
end
+
+ describe '#revert_renames' do
+ it 'renames namespaces' do
+ rename_namespaces = double
+ expect(described_class::RenameNamespaces)
+ .to receive(:new).with([], subject)
+ .and_return(rename_namespaces)
+ expect(rename_namespaces).to receive(:revert_renames)
+
+ subject.revert_renames
+ end
+
+ it 'renames projects' do
+ rename_projects = double
+ expect(described_class::RenameProjects)
+ .to receive(:new).with([], subject)
+ .and_return(rename_projects)
+ expect(rename_projects).to receive(:revert_renames)
+
+ subject.revert_renames
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/sha_attribute_spec.rb b/spec/lib/gitlab/database/sha_attribute_spec.rb
new file mode 100644
index 00000000000..62c1d37ea1c
--- /dev/null
+++ b/spec/lib/gitlab/database/sha_attribute_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Database::ShaAttribute do
+ let(:sha) do
+ '9a573a369a5bfbb9a4a36e98852c21af8a44ea8b'
+ end
+
+ let(:binary_sha) do
+ [sha].pack('H*')
+ end
+
+ let(:binary_from_db) do
+ if Gitlab::Database.postgresql?
+ "\\x#{sha}"
+ else
+ binary_sha
+ end
+ end
+
+ let(:attribute) { described_class.new }
+
+ describe '#type_cast_from_database' do
+ it 'converts the binary SHA to a String' do
+ expect(attribute.type_cast_from_database(binary_from_db)).to eq(sha)
+ end
+ end
+
+ describe '#type_cast_for_database' do
+ it 'converts a SHA String to binary data' do
+ expect(attribute.type_cast_for_database(sha).to_s).to eq(binary_sha)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 5e6206b96c7..c5f9aecd867 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Database, lib: true do
+describe Gitlab::Database do
before do
stub_const('MigrationTest', Class.new { include Gitlab::Database })
end
@@ -176,6 +176,10 @@ describe Gitlab::Database, lib: true do
described_class.bulk_insert('test', rows)
end
+
+ it 'handles non-UTF-8 data' do
+ expect { described_class.bulk_insert('test', [{ a: "\255" }]) }.not_to raise_error
+ end
end
describe '.create_connection_pool' do
diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
index df77f4037af..3a93d5e1e97 100644
--- a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::CartfileLinker, lib: true do
+describe Gitlab::DependencyLinker::CartfileLinker do
describe '.support?' do
it 'supports Cartfile' do
expect(described_class.support?('Cartfile')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
index d7a926e800f..4d222564fd0 100644
--- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::ComposerJsonLinker, lib: true do
+describe Gitlab::DependencyLinker::ComposerJsonLinker do
describe '.support?' do
it 'supports composer.json' do
expect(described_class.support?('composer.json')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
index 3f8335f03ea..a97803b119e 100644
--- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::GemfileLinker, lib: true do
+describe Gitlab::DependencyLinker::GemfileLinker do
describe '.support?' do
it 'supports Gemfile' do
expect(described_class.support?('Gemfile')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
index d4a71403939..24ad7d12f4c 100644
--- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::GemspecLinker, lib: true do
+describe Gitlab::DependencyLinker::GemspecLinker do
describe '.support?' do
it 'supports *.gemspec' do
expect(described_class.support?('gitlab_git.gemspec')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
index e279e0c9019..ae5ad39ad11 100644
--- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::GodepsJsonLinker, lib: true do
+describe Gitlab::DependencyLinker::GodepsJsonLinker do
describe '.support?' do
it 'supports Godeps.json' do
expect(described_class.support?('Godeps.json')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
index 8c979ae1869..1e8b72afb7b 100644
--- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::PackageJsonLinker, lib: true do
+describe Gitlab::DependencyLinker::PackageJsonLinker do
describe '.support?' do
it 'supports package.json' do
expect(described_class.support?('package.json')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
index 06007cf97f7..cdfd7ad9826 100644
--- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::PodfileLinker, lib: true do
+describe Gitlab::DependencyLinker::PodfileLinker do
describe '.support?' do
it 'supports Podfile' do
expect(described_class.support?('Podfile')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
index d722865264b..d4a398c5948 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::PodspecJsonLinker, lib: true do
+describe Gitlab::DependencyLinker::PodspecJsonLinker do
describe '.support?' do
it 'supports *.podspec.json' do
expect(described_class.support?('Reachability.podspec.json')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
index dfc366b5817..ed60ab45955 100644
--- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::PodspecLinker, lib: true do
+describe Gitlab::DependencyLinker::PodspecLinker do
describe '.support?' do
it 'supports *.podspec' do
expect(described_class.support?('Reachability.podspec')).to be_truthy
diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
index 4da8821726c..ef952b3abd5 100644
--- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
+describe Gitlab::DependencyLinker::RequirementsTxtLinker do
describe '.support?' do
it 'supports requirements.txt' do
expect(described_class.support?('requirements.txt')).to be_truthy
@@ -54,6 +54,8 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
Sphinx>=1.3
docutils>=0.7
markupsafe
+ pytest~=3.0
+ foop!=3.0
CONTENT
end
@@ -78,10 +80,16 @@ describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do
expect(subject).to include(link('Sphinx', 'https://pypi.python.org/pypi/Sphinx'))
expect(subject).to include(link('docutils', 'https://pypi.python.org/pypi/docutils'))
expect(subject).to include(link('markupsafe', 'https://pypi.python.org/pypi/markupsafe'))
+ expect(subject).to include(link('pytest', 'https://pypi.python.org/pypi/pytest'))
+ expect(subject).to include(link('foop', 'https://pypi.python.org/pypi/foop'))
end
it 'links URLs' do
expect(subject).to include(link('http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl', 'http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl'))
end
+
+ it 'does not contain link with a newline as package name' do
+ expect(subject).not_to include(link("\n", "https://pypi.python.org/pypi/\n"))
+ end
end
end
diff --git a/spec/lib/gitlab/dependency_linker_spec.rb b/spec/lib/gitlab/dependency_linker_spec.rb
index 3d1cfbcfbf7..10d2f701298 100644
--- a/spec/lib/gitlab/dependency_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab::DependencyLinker, lib: true do
+describe Gitlab::DependencyLinker do
describe '.link' do
it 'links using GemfileLinker' do
blob_name = 'Gemfile'
diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb
index a8173558c00..c73708d90a8 100644
--- a/spec/lib/gitlab/diff/diff_refs_spec.rb
+++ b/spec/lib/gitlab/diff/diff_refs_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::DiffRefs, lib: true do
+describe Gitlab::Diff::DiffRefs do
let(:project) { create(:project, :repository) }
describe '#compare_in' do
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index f289131cc3a..cd2fa98b14c 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::File, lib: true do
+describe Gitlab::Diff::File do
include RepoHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
index 7d7d4a55e63..cd602ccab8e 100644
--- a/spec/lib/gitlab/diff/highlight_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::Highlight, lib: true do
+describe Gitlab::Diff::Highlight do
include RepoHelpers
let(:project) { create(:project, :repository) }
@@ -10,7 +10,7 @@ describe Gitlab::Diff::Highlight, lib: true do
describe '#highlight' do
context "with a diff file" do
- let(:subject) { Gitlab::Diff::Highlight.new(diff_file, repository: project.repository).highlight }
+ let(:subject) { described_class.new(diff_file, repository: project.repository).highlight }
it 'returns Gitlab::Diff::Line elements' do
expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line)
@@ -41,7 +41,7 @@ describe Gitlab::Diff::Highlight, lib: true do
end
context "with diff lines" do
- let(:subject) { Gitlab::Diff::Highlight.new(diff_file.diff_lines, repository: project.repository).highlight }
+ let(:subject) { described_class.new(diff_file.diff_lines, repository: project.repository).highlight }
it 'returns Gitlab::Diff::Line elements' do
expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line)
diff --git a/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb
index d6e8b8ac4b2..046b096e366 100644
--- a/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb
+++ b/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::InlineDiffMarkdownMarker, lib: true do
+describe Gitlab::Diff::InlineDiffMarkdownMarker do
describe '#mark' do
let(:raw) { "abc 'def'" }
let(:inline_diffs) { [2..5] }
diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
index 95da344802d..c3bf34c24ae 100644
--- a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
+++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::InlineDiffMarker, lib: true do
+describe Gitlab::Diff::InlineDiffMarker do
describe '#mark' do
context "when the rich text is html safe" do
let(:raw) { "abc 'def'" }
diff --git a/spec/lib/gitlab/diff/inline_diff_spec.rb b/spec/lib/gitlab/diff/inline_diff_spec.rb
index 8ca3f73509e..15451c2cf99 100644
--- a/spec/lib/gitlab/diff/inline_diff_spec.rb
+++ b/spec/lib/gitlab/diff/inline_diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::InlineDiff, lib: true do
+describe Gitlab::Diff::InlineDiff do
describe '.for_lines' do
let(:diff) do
<<-EOF.strip_heredoc
diff --git a/spec/lib/gitlab/diff/line_mapper_spec.rb b/spec/lib/gitlab/diff/line_mapper_spec.rb
index 2c7ecd1907e..42750bf9ea1 100644
--- a/spec/lib/gitlab/diff/line_mapper_spec.rb
+++ b/spec/lib/gitlab/diff/line_mapper_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::LineMapper, lib: true do
+describe Gitlab::Diff::LineMapper do
include RepoHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/diff/parallel_diff_spec.rb b/spec/lib/gitlab/diff/parallel_diff_spec.rb
index 0f779339c54..e9fc7be366a 100644
--- a/spec/lib/gitlab/diff/parallel_diff_spec.rb
+++ b/spec/lib/gitlab/diff/parallel_diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::ParallelDiff, lib: true do
+describe Gitlab::Diff::ParallelDiff do
include RepoHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb
index e76128ecd87..c71568e2a65 100644
--- a/spec/lib/gitlab/diff/parser_spec.rb
+++ b/spec/lib/gitlab/diff/parser_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe Gitlab::Diff::Parser, lib: true do
+describe Gitlab::Diff::Parser do
include RepoHelpers
let(:project) { create(:project) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.raw_diffs.first }
- let(:parser) { Gitlab::Diff::Parser.new }
+ let(:parser) { described_class.new }
describe '#parse' do
let(:diff) do
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index b3d46e69ccb..d4a2a852c12 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::Position, lib: true do
+describe Gitlab::Diff::Position do
include RepoHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb
index 93d30b90937..8beebc10040 100644
--- a/spec/lib/gitlab/diff/position_tracer_spec.rb
+++ b/spec/lib/gitlab/diff/position_tracer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::PositionTracer, lib: true do
+describe Gitlab::Diff::PositionTracer do
# Douwe's diary New York City, 2016-06-28
# --------------------------------------------------------------------------
#
diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb
index 08b2577ecc4..f61dbc67ad1 100644
--- a/spec/lib/gitlab/email/attachment_uploader_spec.rb
+++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::Email::AttachmentUploader, lib: true do
+describe Gitlab::Email::AttachmentUploader do
describe "#execute" do
let(:project) { build(:project) }
let(:message_raw) { fixture_file("emails/attachment.eml") }
diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
index 4a9c9a7fe34..bd36d1d309d 100644
--- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require_relative '../email_shared_blocks'
-describe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
+describe Gitlab::Email::Handler::CreateIssueHandler do
include_context :email_shared_context
it_behaves_like :reply_processing_shared_examples
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index cd0309e248d..0127b012c91 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require_relative '../email_shared_blocks'
-describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
+describe Gitlab::Email::Handler::CreateNoteHandler do
include_context :email_shared_context
it_behaves_like :reply_processing_shared_examples
diff --git a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
index 0939e6c4514..66c38498e4e 100644
--- a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require_relative '../email_shared_blocks'
-describe Gitlab::Email::Handler::UnsubscribeHandler, lib: true do
+describe Gitlab::Email::Handler::UnsubscribeHandler do
include_context :email_shared_context
before do
diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb
index c6e3524f743..88565ea5311 100644
--- a/spec/lib/gitlab/email/receiver_spec.rb
+++ b/spec/lib/gitlab/email/receiver_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require_relative 'email_shared_blocks'
-describe Gitlab::Email::Receiver, lib: true do
+describe Gitlab::Email::Receiver do
include_context :email_shared_context
context "when the email contains a valid email address in a Delivered-To header" do
diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb
index 2ea5e6460a3..e21a998adfe 100644
--- a/spec/lib/gitlab/email/reply_parser_spec.rb
+++ b/spec/lib/gitlab/email/reply_parser_spec.rb
@@ -1,7 +1,7 @@
require "spec_helper"
# Inspired in great part by Discourse's Email::Receiver
-describe Gitlab::Email::ReplyParser, lib: true do
+describe Gitlab::Email::ReplyParser do
describe '#execute' do
def test_parse_body(mail_string)
described_class.new(Mail::Message.new(mail_string)).execute
diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb
index a366d68a146..c1ed47cf64a 100644
--- a/spec/lib/gitlab/exclusive_lease_spec.rb
+++ b/spec/lib/gitlab/exclusive_lease_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ExclusiveLease, type: :redis do
+describe Gitlab::ExclusiveLease, :clean_gitlab_redis_shared_state do
let(:unique_key) { SecureRandom.hex(10) }
describe '#try_obtain' do
@@ -19,6 +19,19 @@ describe Gitlab::ExclusiveLease, type: :redis do
end
end
+ describe '#renew' do
+ it 'returns true when we have the existing lease' do
+ lease = described_class.new(unique_key, timeout: 3600)
+ expect(lease.try_obtain).to be_present
+ expect(lease.renew).to be_truthy
+ end
+
+ it 'returns false when we dont have a lease' do
+ lease = described_class.new(unique_key, timeout: 3600)
+ expect(lease.renew).to be_falsey
+ end
+ end
+
describe '#exists?' do
it 'returns true for an existing lease' do
lease = described_class.new(unique_key, timeout: 3600)
diff --git a/spec/lib/gitlab/fake_application_settings_spec.rb b/spec/lib/gitlab/fake_application_settings_spec.rb
index b793176d84a..34322c2a693 100644
--- a/spec/lib/gitlab/fake_application_settings_spec.rb
+++ b/spec/lib/gitlab/fake_application_settings_spec.rb
@@ -1,25 +1,25 @@
require 'spec_helper'
describe Gitlab::FakeApplicationSettings do
- let(:defaults) { { signin_enabled: false, foobar: 'asdf', signup_enabled: true, 'test?' => 123 } }
+ let(:defaults) { { password_authentication_enabled: false, foobar: 'asdf', signup_enabled: true, 'test?' => 123 } }
subject { described_class.new(defaults) }
it 'wraps OpenStruct variables properly' do
- expect(subject.signin_enabled).to be_falsey
+ expect(subject.password_authentication_enabled).to be_falsey
expect(subject.signup_enabled).to be_truthy
expect(subject.foobar).to eq('asdf')
end
it 'defines predicate methods' do
- expect(subject.signin_enabled?).to be_falsey
+ expect(subject.password_authentication_enabled?).to be_falsey
expect(subject.signup_enabled?).to be_truthy
end
it 'predicate method changes when value is updated' do
- subject.signin_enabled = true
+ subject.password_authentication_enabled = true
- expect(subject.signin_enabled?).to be_truthy
+ expect(subject.password_authentication_enabled?).to be_truthy
end
it 'does not define a predicate method' do
diff --git a/spec/lib/gitlab/file_finder_spec.rb b/spec/lib/gitlab/file_finder_spec.rb
index 5a32ffd462c..3fb6315a39a 100644
--- a/spec/lib/gitlab/file_finder_spec.rb
+++ b/spec/lib/gitlab/file_finder_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::FileFinder, lib: true do
+describe Gitlab::FileFinder do
describe '#find' do
let(:project) { create(:project, :public, :repository) }
let(:finder) { described_class.new(project, project.default_branch) }
diff --git a/spec/lib/gitlab/fogbugz_import/client_spec.rb b/spec/lib/gitlab/fogbugz_import/client_spec.rb
index 252cd4c55c7..dcd1a2d9813 100644
--- a/spec/lib/gitlab/fogbugz_import/client_spec.rb
+++ b/spec/lib/gitlab/fogbugz_import/client_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::FogbugzImport::Client, lib: true do
+describe Gitlab::FogbugzImport::Client do
let(:client) { described_class.new(uri: '', token: '') }
let(:one_user) { { 'people' => { 'person' => { "ixPerson" => "2", "sFullName" => "James" } } } }
let(:two_users) { { 'people' => { 'person' => [one_user, { "ixPerson" => "3" }] } } }
diff --git a/spec/lib/gitlab/git/blame_spec.rb b/spec/lib/gitlab/git/blame_spec.rb
index 8b041ac69b1..66c016d14b3 100644
--- a/spec/lib/gitlab/git/blame_spec.rb
+++ b/spec/lib/gitlab/git/blame_spec.rb
@@ -20,6 +20,7 @@ describe Gitlab::Git::Blame, seed_helper: true do
expect(data.size).to eq(95)
expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit)
expect(data.first[:line]).to eq("# Contribute to GitLab")
+ expect(data.first[:line]).to be_utf8
end
end
@@ -40,6 +41,7 @@ describe Gitlab::Git::Blame, seed_helper: true do
expect(data.size).to eq(1)
expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit)
expect(data.first[:line]).to eq("Ä ü")
+ expect(data.first[:line]).to be_utf8
end
end
@@ -61,6 +63,7 @@ describe Gitlab::Git::Blame, seed_helper: true do
expect(data.size).to eq(1)
expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit)
expect(data.first[:line]).to eq(" ")
+ expect(data.first[:line]).to be_utf8
end
end
end
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 5b8648392b9..3c784eda4f8 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
- describe '.find' do
+ shared_examples 'finding blobs' do
context 'file in subdir' do
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb") }
@@ -101,7 +101,17 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
- describe '.raw' do
+ describe '.find' do
+ context 'when project_raw_show Gitaly feature is enabled' do
+ it_behaves_like 'finding blobs'
+ end
+
+ context 'when project_raw_show Gitaly feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'finding blobs'
+ end
+ end
+
+ shared_examples 'finding blobs by ID' do
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
it { expect(raw_blob.id).to eq(SeedRepo::RubyBlob::ID) }
it { expect(raw_blob.data[0..10]).to eq("require \'fi") }
@@ -126,6 +136,16 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
+ describe '.raw' do
+ context 'when the blob_raw Gitaly feature is enabled' do
+ it_behaves_like 'finding blobs by ID'
+ end
+
+ context 'when the blob_raw Gitaly feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'finding blobs by ID'
+ end
+ end
+
describe 'encoding' do
context 'file with russian text' do
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "encoding/russian.rb") }
diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb
index 9dba4397e79..cdf1b8beee3 100644
--- a/spec/lib/gitlab/git/branch_spec.rb
+++ b/spec/lib/gitlab/git/branch_spec.rb
@@ -7,51 +7,6 @@ describe Gitlab::Git::Branch, seed_helper: true do
it { is_expected.to be_kind_of Array }
- describe 'initialize' do
- let(:commit_id) { 'f00' }
- let(:commit_subject) { "My commit".force_encoding('ASCII-8BIT') }
- let(:committer) do
- Gitaly::FindLocalBranchCommitAuthor.new(
- name: generate(:name),
- email: generate(:email),
- date: Google::Protobuf::Timestamp.new(seconds: 123)
- )
- end
- let(:author) do
- Gitaly::FindLocalBranchCommitAuthor.new(
- name: generate(:name),
- email: generate(:email),
- date: Google::Protobuf::Timestamp.new(seconds: 456)
- )
- end
- let(:gitaly_branch) do
- Gitaly::FindLocalBranchResponse.new(
- name: 'foo', commit_id: commit_id, commit_subject: commit_subject,
- commit_author: author, commit_committer: committer
- )
- end
- let(:attributes) do
- {
- id: commit_id,
- message: commit_subject,
- authored_date: Time.at(author.date.seconds),
- author_name: author.name,
- author_email: author.email,
- committed_date: Time.at(committer.date.seconds),
- committer_name: committer.name,
- committer_email: committer.email
- }
- end
- let(:branch) { described_class.new(repository, 'foo', gitaly_branch) }
-
- it 'parses Gitaly::FindLocalBranchResponse correctly' do
- expect(Gitlab::Git::Commit).to receive(:decorate)
- .with(hash_including(attributes)).and_call_original
-
- expect(branch.dereferenced_target.message.encoding).to be(Encoding::UTF_8)
- end
- end
-
describe '#size' do
subject { super().size }
it { is_expected.to eq(SeedRepo::Repo::BRANCHES.size) }
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 3e44c577643..730fdb112d9 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -64,6 +64,52 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
+ describe "Commit info from gitaly commit" do
+ let(:id) { 'f00' }
+ let(:subject) { "My commit".force_encoding('ASCII-8BIT') }
+ let(:body) { subject + "My body".force_encoding('ASCII-8BIT') }
+ let(:committer) do
+ Gitaly::CommitAuthor.new(
+ name: generate(:name),
+ email: generate(:email),
+ date: Google::Protobuf::Timestamp.new(seconds: 123)
+ )
+ end
+ let(:author) do
+ Gitaly::CommitAuthor.new(
+ name: generate(:name),
+ email: generate(:email),
+ date: Google::Protobuf::Timestamp.new(seconds: 456)
+ )
+ end
+ let(:gitaly_commit) do
+ Gitaly::GitCommit.new(
+ id: id,
+ subject: subject,
+ body: body,
+ author: author,
+ committer: committer
+ )
+ end
+ let(:commit) { described_class.new(Gitlab::GitalyClient::Commit.new(repository, gitaly_commit)) }
+
+ it { expect(commit.short_id).to eq(id[0..10]) }
+ it { expect(commit.id).to eq(id) }
+ it { expect(commit.sha).to eq(id) }
+ it { expect(commit.safe_message).to eq(body) }
+ it { expect(commit.created_at).to eq(Time.at(committer.date.seconds)) }
+ it { expect(commit.author_email).to eq(author.email) }
+ it { expect(commit.author_name).to eq(author.name) }
+ it { expect(commit.committer_name).to eq(committer.name) }
+ it { expect(commit.committer_email).to eq(committer.email) }
+
+ context 'no body' do
+ let(:body) { "".force_encoding('ASCII-8BIT') }
+
+ it { expect(commit.safe_message).to eq(subject) }
+ end
+ end
+
context 'Class methods' do
describe '.find' do
it "should return first head commit if without params" do
@@ -244,62 +290,85 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
describe '.find_all' do
- context 'max_count' do
- subject do
- commits = Gitlab::Git::Commit.find_all(
- repository,
- max_count: 50
- )
+ shared_examples 'finding all commits' do
+ it 'should return a return a collection of commits' do
+ commits = described_class.find_all(repository)
- commits.map { |c| c.id }
+ expect(commits).to all( be_a_kind_of(Gitlab::Git::Commit) )
end
- it 'has 31 elements' do
- expect(subject.size).to eq(33)
+ context 'max_count' do
+ subject do
+ commits = Gitlab::Git::Commit.find_all(
+ repository,
+ max_count: 50
+ )
+
+ commits.map(&:id)
+ end
+
+ it 'has 33 elements' do
+ expect(subject.size).to eq(33)
+ end
+
+ it 'includes the expected commits' do
+ expect(subject).to include(
+ SeedRepo::Commit::ID,
+ SeedRepo::Commit::PARENT_ID,
+ SeedRepo::FirstCommit::ID
+ )
+ end
end
- it { is_expected.to include(SeedRepo::Commit::ID) }
- it { is_expected.to include(SeedRepo::Commit::PARENT_ID) }
- it { is_expected.to include(SeedRepo::FirstCommit::ID) }
- end
-
- context 'ref + max_count + skip' do
- subject do
- commits = Gitlab::Git::Commit.find_all(
- repository,
- ref: 'master',
- max_count: 50,
- skip: 1
- )
- commits.map { |c| c.id }
+ context 'ref + max_count + skip' do
+ subject do
+ commits = Gitlab::Git::Commit.find_all(
+ repository,
+ ref: 'master',
+ max_count: 50,
+ skip: 1
+ )
+
+ commits.map(&:id)
+ end
+
+ it 'has 24 elements' do
+ expect(subject.size).to eq(24)
+ end
+
+ it 'includes the expected commits' do
+ expect(subject).to include(SeedRepo::Commit::ID, SeedRepo::FirstCommit::ID)
+ expect(subject).not_to include(SeedRepo::LastCommit::ID)
+ end
end
+ end
- it 'has 23 elements' do
- expect(subject.size).to eq(24)
- end
- it { is_expected.to include(SeedRepo::Commit::ID) }
- it { is_expected.to include(SeedRepo::FirstCommit::ID) }
- it { is_expected.not_to include(SeedRepo::LastCommit::ID) }
+ context 'when Gitaly find_all_commits feature is enabled' do
+ it_behaves_like 'finding all commits'
end
- context 'contains feature + max_count' do
- subject do
- commits = Gitlab::Git::Commit.find_all(
- repository,
- contains: 'feature',
- max_count: 7
- )
+ context 'when Gitaly find_all_commits feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'finding all commits'
- commits.map { |c| c.id }
- end
+ context 'while applying a sort order based on the `order` option' do
+ it "allows ordering topologically (no parents shown before their children)" do
+ expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_TOPO)
- it 'has 7 elements' do
- expect(subject.size).to eq(7)
- end
+ described_class.find_all(repository, order: :topo)
+ end
- it { is_expected.not_to include(SeedRepo::Commit::PARENT_ID) }
- it { is_expected.not_to include(SeedRepo::Commit::ID) }
- it { is_expected.to include(SeedRepo::BigCommit::ID) }
+ it "allows ordering by date" do
+ expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_DATE | Rugged::SORT_TOPO)
+
+ described_class.find_all(repository, order: :date)
+ end
+
+ it "applies no sorting by default" do
+ expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_NONE)
+
+ described_class.find_all(repository)
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index d20298fa139..0cfb210e390 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -484,6 +484,8 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do
end
def each
+ return enum_for(:each) unless block_given?
+
loop do
break if @count.zero?
# It is critical to decrement before yielding. We may never reach the lines after 'yield'.
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 5627562abfb..7ea3386ac2a 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -34,7 +34,7 @@ EOT
describe 'size limit feature toggles' do
context 'when the feature gitlab_git_diff_size_limit_increase is enabled' do
before do
- Feature.enable('gitlab_git_diff_size_limit_increase')
+ stub_feature_flags(gitlab_git_diff_size_limit_increase: true)
end
it 'returns 200 KB for size_limit' do
@@ -48,7 +48,7 @@ EOT
context 'when the feature gitlab_git_diff_size_limit_increase is disabled' do
before do
- Feature.disable('gitlab_git_diff_size_limit_increase')
+ stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
end
it 'returns 100 KB for size_limit' do
@@ -175,6 +175,14 @@ EOT
expect(diff).to be_too_large
end
end
+
+ context 'when the patch passed is not UTF-8-encoded' do
+ let(:raw_patch) { @raw_diff_hash[:diff].encode(Encoding::ASCII_8BIT) }
+
+ it 'encodes diff patch to UTF-8' do
+ expect(diff.diff).to be_utf8
+ end
+ end
end
end
@@ -233,7 +241,7 @@ EOT
end
describe '.filter_diff_options' do
- let(:options) { { max_size: 100, invalid_opt: true } }
+ let(:options) { { max_files: 100, invalid_opt: true } }
context "without default options" do
let(:filtered_options) { described_class.filter_diff_options(options) }
@@ -245,7 +253,7 @@ EOT
context "with default options" do
let(:filtered_options) do
- default_options = { max_size: 5, bad_opt: 1, ignore_whitespace: true }
+ default_options = { max_files: 5, bad_opt: 1, ignore_whitespace_change: true }
described_class.filter_diff_options(options, default_options)
end
@@ -255,12 +263,12 @@ EOT
end
it "should merge with default options" do
- expect(filtered_options).to have_key(:ignore_whitespace)
+ expect(filtered_options).to have_key(:ignore_whitespace_change)
end
it "should override default options" do
- expect(filtered_options).to have_key(:max_size)
- expect(filtered_options[:max_size]).to eq(100)
+ expect(filtered_options).to have_key(:max_files)
+ expect(filtered_options[:max_files]).to eq(100)
end
end
end
diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb
index 3f279c21865..19391a70cf6 100644
--- a/spec/lib/gitlab/git/hook_spec.rb
+++ b/spec/lib/gitlab/git/hook_spec.rb
@@ -1,21 +1,29 @@
require 'spec_helper'
require 'fileutils'
-describe Gitlab::Git::Hook, lib: true do
+describe Gitlab::Git::Hook do
+ before do
+ # We need this because in the spec/spec_helper.rb we define it like this:
+ # allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
+ allow_any_instance_of(described_class).to receive(:trigger).and_call_original
+ end
+
describe "#trigger" do
let(:project) { create(:project, :repository) }
+ let(:repo_path) { project.repository.path }
let(:user) { create(:user) }
+ let(:gl_id) { Gitlab::GlId.gl_id(user) }
def create_hook(name)
- FileUtils.mkdir_p(File.join(project.repository.path, 'hooks'))
- File.open(File.join(project.repository.path, 'hooks', name), 'w', 0755) do |f|
+ FileUtils.mkdir_p(File.join(repo_path, 'hooks'))
+ File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f|
f.write('exit 0')
end
end
def create_failing_hook(name)
- FileUtils.mkdir_p(File.join(project.repository.path, 'hooks'))
- File.open(File.join(project.repository.path, 'hooks', name), 'w', 0755) do |f|
+ FileUtils.mkdir_p(File.join(repo_path, 'hooks'))
+ File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f|
f.write(<<-HOOK)
echo 'regular message from the hook'
echo 'error message from the hook' 1>&2
@@ -27,13 +35,29 @@ describe Gitlab::Git::Hook, lib: true do
['pre-receive', 'post-receive', 'update'].each do |hook_name|
context "when triggering a #{hook_name} hook" do
context "when the hook is successful" do
+ let(:hook_path) { File.join(repo_path, 'hooks', hook_name) }
+ let(:gl_repository) { Gitlab::GlRepository.gl_repository(project, false) }
+ let(:env) do
+ {
+ 'GL_ID' => gl_id,
+ 'PWD' => repo_path,
+ 'GL_PROTOCOL' => 'web',
+ 'GL_REPOSITORY' => gl_repository
+ }
+ end
+
it "returns success with no errors" do
create_hook(hook_name)
- hook = Gitlab::Git::Hook.new(hook_name, project.repository.path)
+ hook = described_class.new(hook_name, project)
blank = Gitlab::Git::BLANK_SHA
ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch'
- status, errors = hook.trigger(Gitlab::GlId.gl_id(user), blank, blank, ref)
+ if hook_name != 'update'
+ expect(Open3).to receive(:popen3)
+ .with(env, hook_path, chdir: repo_path).and_call_original
+ end
+
+ status, errors = hook.trigger(gl_id, blank, blank, ref)
expect(status).to be true
expect(errors).to be_blank
end
@@ -42,11 +66,11 @@ describe Gitlab::Git::Hook, lib: true do
context "when the hook is unsuccessful" do
it "returns failure with errors" do
create_failing_hook(hook_name)
- hook = Gitlab::Git::Hook.new(hook_name, project.repository.path)
+ hook = described_class.new(hook_name, project)
blank = Gitlab::Git::BLANK_SHA
ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch'
- status, errors = hook.trigger(Gitlab::GlId.gl_id(user), blank, blank, ref)
+ status, errors = hook.trigger(gl_id, blank, blank, ref)
expect(status).to be false
expect(errors).to eq("error message from the hook\n")
end
@@ -56,11 +80,11 @@ describe Gitlab::Git::Hook, lib: true do
context "when the hook doesn't exist" do
it "returns success with no errors" do
- hook = Gitlab::Git::Hook.new('unknown_hook', project.repository.path)
+ hook = described_class.new('unknown_hook', project)
blank = Gitlab::Git::BLANK_SHA
ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch'
- status, errors = hook.trigger(Gitlab::GlId.gl_id(user), blank, blank, ref)
+ status, errors = hook.trigger(gl_id, blank, blank, ref)
expect(status).to be true
expect(errors).to be_nil
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 703b0c2c202..50736d353ad 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -3,6 +3,20 @@ require "spec_helper"
describe Gitlab::Git::Repository, seed_helper: true do
include Gitlab::EncodingHelper
+ shared_examples 'wrapping gRPC errors' do |gitaly_client_class, gitaly_client_method|
+ it 'wraps gRPC not found error' do
+ expect_any_instance_of(gitaly_client_class).to receive(gitaly_client_method)
+ .and_raise(GRPC::NotFound)
+ expect { subject }.to raise_error(Gitlab::Git::Repository::NoRepository)
+ end
+
+ it 'wraps gRPC unknown error' do
+ expect_any_instance_of(gitaly_client_class).to receive(gitaly_client_method)
+ .and_raise(GRPC::Unknown)
+ expect { subject }.to raise_error(Gitlab::Git::CommandError)
+ end
+ end
+
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
describe "Respond to" do
@@ -26,31 +40,17 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- context 'with gitaly enabled' do
- before do
- stub_gitaly
- end
-
- after do
- Gitlab::GitalyClient.clear_stubs!
- end
-
- it 'gets the branch name from GitalyClient' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name)
- repository.root_ref
- end
+ it 'returns UTF-8' do
+ expect(repository.root_ref).to be_utf8
+ end
- it 'wraps GRPC not found' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name)
- .and_raise(GRPC::NotFound)
- expect { repository.root_ref }.to raise_error(Gitlab::Git::Repository::NoRepository)
- end
+ it 'gets the branch name from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::RefService).to receive(:default_branch_name)
+ repository.root_ref
+ end
- it 'wraps GRPC exceptions' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name)
- .and_raise(GRPC::Unknown)
- expect { repository.root_ref }.to raise_error(Gitlab::Git::CommandError)
- end
+ it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :default_branch_name do
+ subject { repository.root_ref }
end
end
@@ -123,45 +123,35 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'has SeedRepo::Repo::BRANCHES.size elements' do
expect(subject.size).to eq(SeedRepo::Repo::BRANCHES.size)
end
- it { is_expected.to include("master") }
- it { is_expected.not_to include("branch-from-space") }
- context 'with gitaly enabled' do
- before do
- stub_gitaly
- end
-
- after do
- Gitlab::GitalyClient.clear_stubs!
- end
-
- it 'gets the branch names from GitalyClient' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names)
- subject
- end
+ it 'returns UTF-8' do
+ expect(subject.first).to be_utf8
+ end
- it 'wraps GRPC not found' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names)
- .and_raise(GRPC::NotFound)
- expect { subject }.to raise_error(Gitlab::Git::Repository::NoRepository)
- end
+ it { is_expected.to include("master") }
+ it { is_expected.not_to include("branch-from-space") }
- it 'wraps GRPC other exceptions' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names)
- .and_raise(GRPC::Unknown)
- expect { subject }.to raise_error(Gitlab::Git::CommandError)
- end
+ it 'gets the branch names from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::RefService).to receive(:branch_names)
+ subject
end
+
+ it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :branch_names
end
describe '#tag_names' do
subject { repository.tag_names }
it { is_expected.to be_kind_of Array }
+
it 'has SeedRepo::Repo::TAGS.size elements' do
expect(subject.size).to eq(SeedRepo::Repo::TAGS.size)
end
+ it 'returns UTF-8' do
+ expect(subject.first).to be_utf8
+ end
+
describe '#last' do
subject { super().last }
it { is_expected.to eq("v1.2.1") }
@@ -169,32 +159,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.to include("v1.0.0") }
it { is_expected.not_to include("v5.0.0") }
- context 'with gitaly enabled' do
- before do
- stub_gitaly
- end
-
- after do
- Gitlab::GitalyClient.clear_stubs!
- end
-
- it 'gets the tag names from GitalyClient' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names)
- subject
- end
-
- it 'wraps GRPC not found' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names)
- .and_raise(GRPC::NotFound)
- expect { subject }.to raise_error(Gitlab::Git::Repository::NoRepository)
- end
-
- it 'wraps GRPC exceptions' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names)
- .and_raise(GRPC::Unknown)
- expect { subject }.to raise_error(Gitlab::Git::CommandError)
- end
+ it 'gets the tag names from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::RefService).to receive(:tag_names)
+ subject
end
+
+ it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :tag_names
end
shared_examples 'archive check' do |extenstion|
@@ -264,33 +234,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { expect(repository.bare?).to be_truthy }
end
- describe '#heads' do
- let(:heads) { repository.heads }
- subject { heads }
-
- it { is_expected.to be_kind_of Array }
-
- describe '#size' do
- subject { super().size }
- it { is_expected.to eq(SeedRepo::Repo::BRANCHES.size) }
- end
-
- context :head do
- subject { heads.first }
-
- describe '#name' do
- subject { super().name }
- it { is_expected.to eq("feature") }
- end
-
- context :commit do
- subject { heads.first.dereferenced_target.sha }
-
- it { is_expected.to eq("0b4bc9a49b562e85de7cc9e834518ea6828729b9") }
- end
- end
- end
-
describe '#ref_names' do
let(:ref_names) { repository.ref_names }
subject { ref_names }
@@ -308,39 +251,35 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#search_files' do
- let(:results) { repository.search_files('rails', 'master') }
- subject { results }
-
- it { is_expected.to be_kind_of Array }
+ describe '#submodule_url_for' do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
+ let(:ref) { 'master' }
- describe '#first' do
- subject { super().first }
- it { is_expected.to be_kind_of Gitlab::Git::BlobSnippet }
+ def submodule_url(path)
+ repository.submodule_url_for(ref, path)
end
- context 'blob result' do
- subject { results.first }
+ it { expect(submodule_url('six')).to eq('git://github.com/randx/six.git') }
+ it { expect(submodule_url('nested/six')).to eq('git://github.com/randx/six.git') }
+ it { expect(submodule_url('deeper/nested/six')).to eq('git://github.com/randx/six.git') }
+ it { expect(submodule_url('invalid/path')).to eq(nil) }
- describe '#ref' do
- subject { super().ref }
- it { is_expected.to eq('master') }
- end
+ context 'uncommitted submodule dir' do
+ let(:ref) { 'fix-existing-submodule-dir' }
- describe '#filename' do
- subject { super().filename }
- it { is_expected.to eq('CHANGELOG') }
- end
+ it { expect(submodule_url('submodule-existing-dir')).to eq(nil) }
+ end
- describe '#startline' do
- subject { super().startline }
- it { is_expected.to eq(35) }
- end
+ context 'tags' do
+ let(:ref) { 'v1.2.1' }
- describe '#data' do
- subject { super().data }
- it { is_expected.to include "Ability to filter by multiple labels" }
- end
+ it { expect(submodule_url('six')).to eq('git://github.com/randx/six.git') }
+ end
+
+ context 'no submodules at commit' do
+ let(:ref) { '6d39438' }
+
+ it { expect(submodule_url('six')).to eq(nil) }
end
end
@@ -348,7 +287,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
context 'where repo has submodules' do
- let(:submodules) { repository.submodules('master') }
+ let(:submodules) { repository.send(:submodules, 'master') }
let(:submodule) { submodules.first }
it { expect(submodules).to be_kind_of Hash }
@@ -383,12 +322,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
it 'should not have an entry for an uncommited submodule dir' do
- submodules = repository.submodules('fix-existing-submodule-dir')
+ submodules = repository.send(:submodules, 'fix-existing-submodule-dir')
expect(submodules).not_to have_key('submodule-existing-dir')
end
it 'should handle tags correctly' do
- submodules = repository.submodules('v1.2.1')
+ submodules = repository.send(:submodules, 'v1.2.1')
expect(submodules.first).to eq([
"six", {
@@ -414,7 +353,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
context 'where repo doesn\'t have submodules' do
- let(:submodules) { repository.submodules('6d39438') }
+ let(:submodules) { repository.send(:submodules, '6d39438') }
it 'should return an empty hash' do
expect(submodules).to be_empty
end
@@ -422,145 +361,20 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#commit_count' do
- it { expect(repository.commit_count("master")).to eq(25) }
- it { expect(repository.commit_count("feature")).to eq(9) }
- end
-
- describe "#reset" do
- change_path = File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, "CHANGELOG")
- untracked_path = File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, "UNTRACKED")
- tracked_path = File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, "files", "ruby", "popen.rb")
-
- change_text = "New changelog text"
- untracked_text = "This file is untracked"
-
- reset_commit = SeedRepo::LastCommit::ID
-
- context "--hard" do
- before(:all) do
- # Modify a tracked file
- File.open(change_path, "w") do |f|
- f.write(change_text)
- end
-
- # Add an untracked file to the working directory
- File.open(untracked_path, "w") do |f|
- f.write(untracked_text)
- end
-
- @normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH)
- @normal_repo.reset("HEAD", :hard)
- end
-
- it "should replace the working directory with the content of the index" do
- File.open(change_path, "r") do |f|
- expect(f.each_line.first).not_to eq(change_text)
- end
-
- File.open(tracked_path, "r") do |f|
- expect(f.each_line.to_a[8]).to include('raise RuntimeError, "System commands')
- end
- end
-
- it "should not touch untracked files" do
- expect(File.exist?(untracked_path)).to be_truthy
- end
-
- it "should move the HEAD to the correct commit" do
- new_head = @normal_repo.rugged.head.target.oid
- expect(new_head).to eq(reset_commit)
- end
-
- it "should move the tip of the master branch to the correct commit" do
- new_tip = @normal_repo.rugged.references["refs/heads/master"]
- .target.oid
-
- expect(new_tip).to eq(reset_commit)
- end
-
- after(:all) do
- # Fast-forward to the original HEAD
- FileUtils.rm_rf(TEST_NORMAL_REPO_PATH)
- ensure_seeds
- end
+ shared_examples 'counting commits' do
+ it { expect(repository.commit_count("master")).to eq(25) }
+ it { expect(repository.commit_count("feature")).to eq(9) }
end
- end
-
- describe "#checkout" do
- new_branch = "foo_branch"
-
- context "-b" do
- before(:all) do
- @normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH)
- @normal_repo.checkout(new_branch, { b: true }, "origin/feature")
- end
- it "should create a new branch" do
- expect(@normal_repo.rugged.branches[new_branch]).not_to be_nil
- end
-
- it "should move the HEAD to the correct commit" do
- expect(@normal_repo.rugged.head.target.oid).to(
- eq(@normal_repo.rugged.branches["origin/feature"].target.oid)
- )
- end
-
- it "should refresh the repo's #heads collection" do
- head_names = @normal_repo.heads.map { |h| h.name }
- expect(head_names).to include(new_branch)
- end
-
- after(:all) do
- FileUtils.rm_rf(TEST_NORMAL_REPO_PATH)
- ensure_seeds
+ context 'when Gitaly commit_count feature is enabled' do
+ it_behaves_like 'counting commits'
+ it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::CommitService, :commit_count do
+ subject { repository.commit_count('master') }
end
end
- context "without -b" do
- context "and specifying a nonexistent branch" do
- it "should not do anything" do
- normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH)
-
- expect { normal_repo.checkout(new_branch) }.to raise_error(Rugged::ReferenceError)
- expect(normal_repo.rugged.branches[new_branch]).to be_nil
- expect(normal_repo.rugged.head.target.oid).to(
- eq(normal_repo.rugged.branches["master"].target.oid)
- )
-
- head_names = normal_repo.heads.map { |h| h.name }
- expect(head_names).not_to include(new_branch)
- end
-
- after(:all) do
- FileUtils.rm_rf(TEST_NORMAL_REPO_PATH)
- ensure_seeds
- end
- end
-
- context "and with a valid branch" do
- before(:all) do
- @normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH)
- @normal_repo.rugged.branches.create("feature", "origin/feature")
- @normal_repo.checkout("feature")
- end
-
- it "should move the HEAD to the correct commit" do
- expect(@normal_repo.rugged.head.target.oid).to(
- eq(@normal_repo.rugged.branches["feature"].target.oid)
- )
- end
-
- it "should update the working directory" do
- File.open(File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, ".gitignore"), "r") do |f|
- expect(f.read.each_line.to_a).not_to include(".DS_Store\n")
- end
- end
-
- after(:all) do
- FileUtils.rm_rf(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH)
- ensure_seeds
- end
- end
+ context 'when Gitaly commit_count feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'counting commits'
end
end
@@ -574,10 +388,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(@repo.rugged.branches["feature"]).to be_nil
end
- it "should update the repo's #heads collection" do
- expect(@repo.heads).not_to include("feature")
- end
-
after(:all) do
FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
ensure_seeds
@@ -690,9 +500,9 @@ describe Gitlab::Git::Repository, seed_helper: true do
# Add new commits so that there's a renamed file in the commit history
repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH).rugged
- commit_with_old_name = new_commit_edit_old_file(repo)
- rename_commit = new_commit_move_file(repo)
- commit_with_new_name = new_commit_edit_new_file(repo)
+ commit_with_old_name = Gitlab::Git::Commit.decorate(new_commit_edit_old_file(repo))
+ rename_commit = Gitlab::Git::Commit.decorate(new_commit_move_file(repo))
+ commit_with_new_name = Gitlab::Git::Commit.decorate(new_commit_edit_new_file(repo))
end
after(:context) do
@@ -865,8 +675,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
context "compare results between log_by_walk and log_by_shell" do
let(:options) { { ref: "master" } }
- let(:commits_by_walk) { repository.log(options).map(&:oid) }
- let(:commits_by_shell) { repository.log(options.merge({ disable_walk: true })).map(&:oid) }
+ let(:commits_by_walk) { repository.log(options).map(&:id) }
+ let(:commits_by_shell) { repository.log(options.merge({ disable_walk: true })).map(&:id) }
it { expect(commits_by_walk).to eq(commits_by_shell) }
@@ -909,7 +719,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(commits.size).to be > 0
expect(commits).to satisfy do |commits|
- commits.all? { |commit| commit.time >= options[:after] }
+ commits.all? { |commit| commit.committed_date >= options[:after] }
end
end
end
@@ -922,7 +732,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(commits.size).to be > 0
expect(commits).to satisfy do |commits|
- commits.all? { |commit| commit.time <= options[:before] }
+ commits.all? { |commit| commit.committed_date <= options[:before] }
end
end
end
@@ -931,7 +741,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
def commit_files(commit)
- commit.diff(commit.parent_ids.first).deltas.flat_map do |delta|
+ commit.diff_from_parent.deltas.flat_map do |delta|
[delta.old_file[:path], delta.new_file[:path]].uniq.compact
end
end
@@ -1101,48 +911,49 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#find_commits' do
- it 'should return a return a collection of commits' do
- commits = repository.find_commits
+ describe '#branches' do
+ subject { repository.branches }
- expect(commits).not_to be_empty
- expect(commits).to all( be_a_kind_of(Gitlab::Git::Commit) )
- end
+ context 'with local and remote branches' do
+ let(:repository) do
+ Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'))
+ end
- context 'while applying a sort order based on the `order` option' do
- it "allows ordering topologically (no parents shown before their children)" do
- expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_TOPO)
+ before do
+ create_remote_branch(repository, 'joe', 'remote_branch', 'master')
+ repository.create_branch('local_branch', 'master')
+ end
- repository.find_commits(order: :topo)
+ after do
+ FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
+ ensure_seeds
end
- it "allows ordering by date" do
- expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_DATE | Rugged::SORT_TOPO)
+ it 'returns the local and remote branches' do
+ expect(subject.any? { |b| b.name == 'joe/remote_branch' }).to eq(true)
+ expect(subject.any? { |b| b.name == 'local_branch' }).to eq(true)
+ end
+ end
- repository.find_commits(order: :date)
+ # With Gitaly enabled, Gitaly just doesn't return deleted branches.
+ context 'with deleted branch with Gitaly disabled' do
+ before do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
end
- it "applies no sorting by default" do
- expect_any_instance_of(Rugged::Walker).to receive(:sorting).with(Rugged::SORT_NONE)
+ it 'returns no results' do
+ ref = double()
+ allow(ref).to receive(:name) { 'bad-branch' }
+ allow(ref).to receive(:target) { raise Rugged::ReferenceError }
+ branches = double()
+ allow(branches).to receive(:each) { [ref].each }
+ allow(repository.rugged).to receive(:branches) { branches }
- repository.find_commits
+ expect(subject).to be_empty
end
end
- end
-
- describe '#branches with deleted branch' do
- before(:each) do
- ref = double()
- allow(ref).to receive(:name) { 'bad-branch' }
- allow(ref).to receive(:target) { raise Rugged::ReferenceError }
- branches = double()
- allow(branches).to receive(:each) { [ref].each }
- allow(repository.rugged).to receive(:branches) { branches }
- end
- it 'should return empty branches' do
- expect(repository.branches).to eq([])
- end
+ it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :branches
end
describe '#branch_count' do
@@ -1289,45 +1100,36 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
it 'returns the local branches' do
- create_remote_branch('joe', 'remote_branch', 'master')
+ create_remote_branch(@repo, 'joe', 'remote_branch', 'master')
@repo.create_branch('local_branch', 'master')
expect(@repo.local_branches.any? { |branch| branch.name == 'remote_branch' }).to eq(false)
expect(@repo.local_branches.any? { |branch| branch.name == 'local_branch' }).to eq(true)
end
- context 'with gitaly enabled' do
- before do
- stub_gitaly
- end
-
- after do
- Gitlab::GitalyClient.clear_stubs!
- end
-
- it 'gets the branches from GitalyClient' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:local_branches)
- .and_return([])
- @repo.local_branches
+ it 'returns a Branch with UTF-8 fields' do
+ branches = @repo.local_branches.to_a
+ expect(branches.size).to be > 0
+ branches.each do |branch|
+ expect(branch.name).to be_utf8
+ expect(branch.target).to be_utf8 unless branch.target.nil?
end
+ end
- it 'wraps GRPC not found' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:local_branches)
- .and_raise(GRPC::NotFound)
- expect { @repo.local_branches }.to raise_error(Gitlab::Git::Repository::NoRepository)
- end
+ it 'gets the branches from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::RefService).to receive(:local_branches)
+ .and_return([])
+ @repo.local_branches
+ end
- it 'wraps GRPC exceptions' do
- expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:local_branches)
- .and_raise(GRPC::Unknown)
- expect { @repo.local_branches }.to raise_error(Gitlab::Git::CommandError)
- end
+ it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :local_branches do
+ subject { @repo.local_branches }
end
end
- def create_remote_branch(remote_name, branch_name, source_branch_name)
- source_branch = @repo.branches.find { |branch| branch.name == source_branch_name }
- rugged = @repo.rugged
+ def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
+ source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
+ rugged = repository.rugged
rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", source_branch.dereferenced_target.sha)
end
@@ -1400,11 +1202,4 @@ describe Gitlab::Git::Repository, seed_helper: true do
sha = Rugged::Commit.create(repo, options)
repo.lookup(sha)
end
-
- def stub_gitaly
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
-
- stub = double(:stub)
- allow(Gitaly::Ref::Stub).to receive(:new).and_return(stub)
- end
end
diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb
index 78894ba9409..b051a088171 100644
--- a/spec/lib/gitlab/git/rev_list_spec.rb
+++ b/spec/lib/gitlab/git/rev_list_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Git::RevList, lib: true do
+describe Gitlab::Git::RevList do
let(:project) { create(:project, :repository) }
before do
@@ -11,7 +11,7 @@ describe Gitlab::Git::RevList, lib: true do
end
context "#new_refs" do
- let(:rev_list) { Gitlab::Git::RevList.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
+ let(:rev_list) { described_class.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
it 'calls out to `popen`' do
expect(Gitlab::Popen).to receive(:popen).with([
@@ -33,7 +33,7 @@ describe Gitlab::Git::RevList, lib: true do
end
context "#missed_ref" do
- let(:rev_list) { Gitlab::Git::RevList.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
+ let(:rev_list) { described_class.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) }
it 'calls out to `popen`' do
expect(Gitlab::Popen).to receive(:popen).with([
diff --git a/spec/lib/gitlab/git/tag_spec.rb b/spec/lib/gitlab/git/tag_spec.rb
index 67a9c974298..78d1e120013 100644
--- a/spec/lib/gitlab/git/tag_spec.rb
+++ b/spec/lib/gitlab/git/tag_spec.rb
@@ -3,23 +3,33 @@ require "spec_helper"
describe Gitlab::Git::Tag, seed_helper: true do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
- describe 'first tag' do
- let(:tag) { repository.tags.first }
+ shared_examples 'Gitlab::Git::Repository#tags' do
+ describe 'first tag' do
+ let(:tag) { repository.tags.first }
- it { expect(tag.name).to eq("v1.0.0") }
- it { expect(tag.target).to eq("f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8") }
- it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") }
- it { expect(tag.message).to eq("Release") }
- end
+ it { expect(tag.name).to eq("v1.0.0") }
+ it { expect(tag.target).to eq("f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8") }
+ it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") }
+ it { expect(tag.message).to eq("Release") }
+ end
+
+ describe 'last tag' do
+ let(:tag) { repository.tags.last }
- describe 'last tag' do
- let(:tag) { repository.tags.last }
+ it { expect(tag.name).to eq("v1.2.1") }
+ it { expect(tag.target).to eq("2ac1f24e253e08135507d0830508febaaccf02ee") }
+ it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") }
+ it { expect(tag.message).to eq("Version 1.2.1") }
+ end
- it { expect(tag.name).to eq("v1.2.1") }
- it { expect(tag.target).to eq("2ac1f24e253e08135507d0830508febaaccf02ee") }
- it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") }
- it { expect(tag.message).to eq("Version 1.2.1") }
+ it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
end
- it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) }
+ context 'when Gitaly tags feature is enabled' do
+ it_behaves_like 'Gitlab::Git::Repository#tags'
+ end
+
+ context 'when Gitaly tags feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'Gitlab::Git::Repository#tags'
+ end
end
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 4b76a43e6b5..98ddd3c3664 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -1,8 +1,9 @@
require "spec_helper"
describe Gitlab::Git::Tree, seed_helper: true do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
+
context :repo do
- let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
let(:tree) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID) }
it { expect(tree).to be_kind_of Array }
@@ -74,4 +75,24 @@ describe Gitlab::Git::Tree, seed_helper: true do
it { expect(submodule.name).to eq('gitlab-shell') }
end
end
+
+ describe '#where' do
+ context 'with gitaly disabled' do
+ before do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
+ end
+
+ it 'calls #tree_entries_from_rugged' do
+ expect(described_class).to receive(:tree_entries_from_rugged)
+
+ described_class.where(repository, SeedRepo::Commit::ID, '/')
+ end
+ end
+
+ it 'gets the tree entries from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::CommitService).to receive(:tree_entries)
+
+ described_class.where(repository, SeedRepo::Commit::ID, '/')
+ end
+ end
end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 9a86cfa66e4..2d6ea37d0ac 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::GitAccess, lib: true do
+describe Gitlab::GitAccess do
let(:pull_access_check) { access.check('git-upload-pack', '_any') }
let(:push_access_check) { access.check('git-receive-pack', '_any') }
- let(:access) { Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
+ let(:access) { described_class.new(actor, project, protocol, authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:actor) { user }
@@ -280,7 +280,7 @@ describe Gitlab::GitAccess, lib: true do
context 'when project is public' do
let(:public_project) { create(:project, :public, :repository) }
- let(:access) { Gitlab::GitAccess.new(nil, public_project, 'web', authentication_abilities: []) }
+ let(:access) { described_class.new(nil, public_project, 'web', authentication_abilities: []) }
context 'when repository is enabled' do
it 'give access to download code' do
@@ -441,7 +441,7 @@ describe Gitlab::GitAccess, lib: true do
end
permissions_matrix[role].each do |action, allowed|
- context action do
+ context action.to_s do
subject { access.send(:check_push_access!, changes[action]) }
it do
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 797ec8cb23e..0376b4ee783 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::GitAccessWiki, lib: true do
- let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
+describe Gitlab::GitAccessWiki do
+ let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:redirected_path) { nil }
diff --git a/spec/lib/gitlab/git_ref_validator_spec.rb b/spec/lib/gitlab/git_ref_validator_spec.rb
index cc8daa535d6..e1fa8ae03f8 100644
--- a/spec/lib/gitlab/git_ref_validator_spec.rb
+++ b/spec/lib/gitlab/git_ref_validator_spec.rb
@@ -1,25 +1,25 @@
require 'spec_helper'
-describe Gitlab::GitRefValidator, lib: true do
- it { expect(Gitlab::GitRefValidator.validate('feature/new')).to be_truthy }
- it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy }
- it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy }
- it { expect(Gitlab::GitRefValidator.validate('#1')).to be_truthy }
- it { expect(Gitlab::GitRefValidator.validate('feature/refs/heads/foo')).to be_truthy }
- it { expect(Gitlab::GitRefValidator.validate('feature/~new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/^new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/:new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/?new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/*new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/[new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/new/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature/new.')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature\@{')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature\new')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature//new')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('feature new')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('refs/heads/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('refs/remotes/')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('refs/heads/feature')).to be_falsey }
- it { expect(Gitlab::GitRefValidator.validate('refs/remotes/origin')).to be_falsey }
+describe Gitlab::GitRefValidator do
+ it { expect(described_class.validate('feature/new')).to be_truthy }
+ it { expect(described_class.validate('implement_@all')).to be_truthy }
+ it { expect(described_class.validate('my_new_feature')).to be_truthy }
+ it { expect(described_class.validate('#1')).to be_truthy }
+ it { expect(described_class.validate('feature/refs/heads/foo')).to be_truthy }
+ it { expect(described_class.validate('feature/~new/')).to be_falsey }
+ it { expect(described_class.validate('feature/^new/')).to be_falsey }
+ it { expect(described_class.validate('feature/:new/')).to be_falsey }
+ it { expect(described_class.validate('feature/?new/')).to be_falsey }
+ it { expect(described_class.validate('feature/*new/')).to be_falsey }
+ it { expect(described_class.validate('feature/[new/')).to be_falsey }
+ it { expect(described_class.validate('feature/new/')).to be_falsey }
+ it { expect(described_class.validate('feature/new.')).to be_falsey }
+ it { expect(described_class.validate('feature\@{')).to be_falsey }
+ it { expect(described_class.validate('feature\new')).to be_falsey }
+ it { expect(described_class.validate('feature//new')).to be_falsey }
+ it { expect(described_class.validate('feature new')).to be_falsey }
+ it { expect(described_class.validate('refs/heads/')).to be_falsey }
+ it { expect(described_class.validate('refs/remotes/')).to be_falsey }
+ it { expect(described_class.validate('refs/heads/feature')).to be_falsey }
+ it { expect(described_class.validate('refs/remotes/origin')).to be_falsey }
end
diff --git a/spec/lib/gitlab/git_spec.rb b/spec/lib/gitlab/git_spec.rb
index 36f0e6507c8..4702a978f19 100644
--- a/spec/lib/gitlab/git_spec.rb
+++ b/spec/lib/gitlab/git_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe Gitlab::Git, lib: true do
+describe Gitlab::Git do
let(:committer_email) { 'user@example.org' }
let(:committer_name) { 'John Doe' }
describe 'committer_hash' do
it "returns a hash containing the given email and name" do
- committer_hash = Gitlab::Git.committer_hash(email: committer_email, name: committer_name)
+ committer_hash = described_class.committer_hash(email: committer_email, name: committer_name)
expect(committer_hash[:email]).to eq(committer_email)
expect(committer_hash[:name]).to eq(committer_name)
@@ -15,7 +15,7 @@ describe Gitlab::Git, lib: true do
context 'when email is nil' do
it "returns nil" do
- committer_hash = Gitlab::Git.committer_hash(email: nil, name: committer_name)
+ committer_hash = described_class.committer_hash(email: nil, name: committer_name)
expect(committer_hash).to be_nil
end
@@ -23,7 +23,7 @@ describe Gitlab::Git, lib: true do
context 'when name is nil' do
it "returns nil" do
- committer_hash = Gitlab::Git.committer_hash(email: committer_email, name: nil)
+ committer_hash = described_class.committer_hash(email: committer_email, name: nil)
expect(committer_hash).to be_nil
end
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
new file mode 100644
index 00000000000..0868c793a33
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -0,0 +1,123 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::CommitService do
+ let(:project) { create(:project, :repository) }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
+ let(:repository) { project.repository }
+ let(:repository_message) { repository.gitaly_repository }
+ let(:revision) { '913c66a37b4a45b9769037c55c2d238bd0942d2e' }
+ let(:commit) { project.commit(revision) }
+ let(:client) { described_class.new(repository) }
+
+ describe '#diff_from_parent' do
+ context 'when a commit has a parent' do
+ it 'sends an RPC request with the parent ID as left commit' do
+ request = Gitaly::CommitDiffRequest.new(
+ repository: repository_message,
+ left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
+ right_commit_id: commit.id,
+ collapse_diffs: true,
+ enforce_limits: true,
+ **Gitlab::Git::DiffCollection.collection_limits.to_h
+ )
+
+ expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
+
+ client.diff_from_parent(commit)
+ end
+ end
+
+ context 'when a commit does not have a parent' do
+ it 'sends an RPC request with empty tree ref as left commit' do
+ initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
+ request = Gitaly::CommitDiffRequest.new(
+ repository: repository_message,
+ left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
+ right_commit_id: initial_commit.id,
+ collapse_diffs: true,
+ enforce_limits: true,
+ **Gitlab::Git::DiffCollection.collection_limits.to_h
+ )
+
+ expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
+
+ client.diff_from_parent(initial_commit)
+ end
+ end
+
+ it 'returns a Gitlab::Git::DiffCollection' do
+ ret = client.diff_from_parent(commit)
+
+ expect(ret).to be_kind_of(Gitlab::Git::DiffCollection)
+ end
+
+ it 'passes options to Gitlab::Git::DiffCollection' do
+ options = { max_files: 31, max_lines: 13, from_gitaly: true }
+
+ expect(Gitlab::Git::DiffCollection).to receive(:new).with(kind_of(Enumerable), options)
+
+ client.diff_from_parent(commit, options)
+ end
+ end
+
+ describe '#commit_deltas' do
+ context 'when a commit has a parent' do
+ it 'sends an RPC request with the parent ID as left commit' do
+ request = Gitaly::CommitDeltaRequest.new(
+ repository: repository_message,
+ left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
+ right_commit_id: commit.id
+ )
+
+ expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_delta).with(request, kind_of(Hash)).and_return([])
+
+ client.commit_deltas(commit)
+ end
+ end
+
+ context 'when a commit does not have a parent' do
+ it 'sends an RPC request with empty tree ref as left commit' do
+ initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
+ request = Gitaly::CommitDeltaRequest.new(
+ repository: repository_message,
+ left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
+ right_commit_id: initial_commit.id
+ )
+
+ expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_delta).with(request, kind_of(Hash)).and_return([])
+
+ client.commit_deltas(initial_commit)
+ end
+ end
+ end
+
+ describe '#between' do
+ let(:from) { 'master' }
+ let(:to) { '4b825dc642cb6eb9a060e54bf8d69288fbee4904' }
+
+ it 'sends an RPC request' do
+ request = Gitaly::CommitsBetweenRequest.new(
+ repository: repository_message, from: from, to: to
+ )
+
+ expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:commits_between)
+ .with(request, kind_of(Hash)).and_return([])
+
+ described_class.new(repository).between(from, to)
+ end
+ end
+
+ describe '#tree_entries' do
+ let(:path) { '/' }
+
+ it 'sends a get_tree_entries message' do
+ expect_any_instance_of(Gitaly::CommitService::Stub)
+ .to receive(:get_tree_entries)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return([])
+
+ client.tree_entries(repository, revision, path)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client/commit_spec.rb b/spec/lib/gitlab/gitaly_client/commit_spec.rb
deleted file mode 100644
index dff5b25c712..00000000000
--- a/spec/lib/gitlab/gitaly_client/commit_spec.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::GitalyClient::Commit do
- let(:diff_stub) { double('Gitaly::Diff::Stub') }
- let(:project) { create(:project, :repository) }
- let(:repository) { project.repository }
- let(:repository_message) { repository.gitaly_repository }
- let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
-
- describe '#diff_from_parent' do
- context 'when a commit has a parent' do
- it 'sends an RPC request with the parent ID as left commit' do
- request = Gitaly::CommitDiffRequest.new(
- repository: repository_message,
- left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
- right_commit_id: commit.id
- )
-
- expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
-
- described_class.new(repository).diff_from_parent(commit)
- end
- end
-
- context 'when a commit does not have a parent' do
- it 'sends an RPC request with empty tree ref as left commit' do
- initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
- request = Gitaly::CommitDiffRequest.new(
- repository: repository_message,
- left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
- right_commit_id: initial_commit.id
- )
-
- expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
-
- described_class.new(repository).diff_from_parent(initial_commit)
- end
- end
-
- it 'returns a Gitlab::Git::DiffCollection' do
- ret = described_class.new(repository).diff_from_parent(commit)
-
- expect(ret).to be_kind_of(Gitlab::Git::DiffCollection)
- end
-
- it 'passes options to Gitlab::Git::DiffCollection' do
- options = { max_files: 31, max_lines: 13 }
-
- expect(Gitlab::Git::DiffCollection).to receive(:new).with(kind_of(Enumerable), options)
-
- described_class.new(repository).diff_from_parent(commit, options)
- end
- end
-
- describe '#commit_deltas' do
- context 'when a commit has a parent' do
- it 'sends an RPC request with the parent ID as left commit' do
- request = Gitaly::CommitDeltaRequest.new(
- repository: repository_message,
- left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
- right_commit_id: commit.id
- )
-
- expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_delta).with(request, kind_of(Hash)).and_return([])
-
- described_class.new(repository).commit_deltas(commit)
- end
- end
-
- context 'when a commit does not have a parent' do
- it 'sends an RPC request with empty tree ref as left commit' do
- initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
- request = Gitaly::CommitDeltaRequest.new(
- repository: repository_message,
- left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
- right_commit_id: initial_commit.id
- )
-
- expect_any_instance_of(Gitaly::Diff::Stub).to receive(:commit_delta).with(request, kind_of(Hash)).and_return([])
-
- described_class.new(repository).commit_deltas(initial_commit)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/gitaly_client/diff_spec.rb b/spec/lib/gitlab/gitaly_client/diff_spec.rb
index 2960c9a79ad..00a31ac0b96 100644
--- a/spec/lib/gitlab/gitaly_client/diff_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitalyClient::Diff, lib: true do
+describe Gitlab::GitalyClient::Diff do
let(:diff_fields) do
{
to_path: ".gitmodules",
diff --git a/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb b/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb
index 07650013052..cd3242b9326 100644
--- a/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitalyClient::DiffStitcher, lib: true do
+describe Gitlab::GitalyClient::DiffStitcher do
describe 'enumeration' do
it 'combines segregated diff messages together' do
diff_1 = OpenStruct.new(
diff --git a/spec/lib/gitlab/gitaly_client/notifications_spec.rb b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb
index 7404ffe0f06..d9597c4aa78 100644
--- a/spec/lib/gitlab/gitaly_client/notifications_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitalyClient::Notifications do
+describe Gitlab::GitalyClient::NotificationService do
describe '#post_receive' do
let(:project) { create(:empty_project) }
let(:storage_name) { project.repository_storage }
@@ -8,7 +8,7 @@ describe Gitlab::GitalyClient::Notifications do
subject { described_class.new(project.repository) }
it 'sends a post_receive message' do
- expect_any_instance_of(Gitaly::Notifications::Stub)
+ expect_any_instance_of(Gitaly::NotificationService::Stub)
.to receive(:post_receive).with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
subject.post_receive
diff --git a/spec/lib/gitlab/gitaly_client/ref_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
index 42dba2ff874..0b1c890f956 100644
--- a/spec/lib/gitlab/gitaly_client/ref_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
@@ -1,25 +1,25 @@
require 'spec_helper'
-describe Gitlab::GitalyClient::Ref do
+describe Gitlab::GitalyClient::RefService do
let(:project) { create(:empty_project) }
let(:storage_name) { project.repository_storage }
let(:relative_path) { project.path_with_namespace + '.git' }
let(:client) { described_class.new(project.repository) }
- before do
- allow(Gitlab.config.gitaly).to receive(:enabled).and_return(true)
- end
+ describe '#branches' do
+ it 'sends a find_all_branches message' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:find_all_branches)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return([])
- after do
- # When we say `expect_any_instance_of(Gitaly::Ref::Stub)` a double is created,
- # and because GitalyClient shares stubs these will get passed from example to
- # example, which will cause an error, so we clean the stubs after each example.
- Gitlab::GitalyClient.clear_stubs!
+ client.branches
+ end
end
describe '#branch_names' do
it 'sends a find_all_branch_names message' do
- expect_any_instance_of(Gitaly::Ref::Stub)
+ expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_all_branch_names)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return([])
@@ -30,7 +30,7 @@ describe Gitlab::GitalyClient::Ref do
describe '#tag_names' do
it 'sends a find_all_tag_names message' do
- expect_any_instance_of(Gitaly::Ref::Stub)
+ expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_all_tag_names)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return([])
@@ -41,7 +41,7 @@ describe Gitlab::GitalyClient::Ref do
describe '#default_branch_name' do
it 'sends a find_default_branch_name message' do
- expect_any_instance_of(Gitaly::Ref::Stub)
+ expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_default_branch_name)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return(double(name: 'foo'))
@@ -52,7 +52,7 @@ describe Gitlab::GitalyClient::Ref do
describe '#local_branches' do
it 'sends a find_local_branches message' do
- expect_any_instance_of(Gitaly::Ref::Stub)
+ expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_local_branches)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return([])
@@ -61,7 +61,7 @@ describe Gitlab::GitalyClient::Ref do
end
it 'parses and sends the sort parameter' do
- expect_any_instance_of(Gitaly::Ref::Stub)
+ expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_local_branches)
.with(gitaly_request_with_params(sort_by: :UPDATED_DESC), kind_of(Hash))
.and_return([])
@@ -69,8 +69,26 @@ describe Gitlab::GitalyClient::Ref do
client.local_branches(sort_by: 'updated_desc')
end
+ it 'translates known mismatches on sort param values' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:find_local_branches)
+ .with(gitaly_request_with_params(sort_by: :NAME), kind_of(Hash))
+ .and_return([])
+
+ client.local_branches(sort_by: 'name_asc')
+ end
+
it 'raises an argument error if an invalid sort_by parameter is passed' do
expect { client.local_branches(sort_by: 'invalid_sort') }.to raise_error(ArgumentError)
end
end
+
+ describe '#find_ref_name', seed_helper: true do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
+ let(:client) { described_class.new(repository) }
+ subject { client.find_ref_name(SeedRepo::Commit::ID, 'refs/heads/master') }
+
+ it { is_expected.to be_utf8 }
+ it { is_expected.to eq('refs/heads/master') }
+ end
end
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
new file mode 100644
index 00000000000..5a9f3fc130c
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::RepositoryService do
+ set(:project) { create(:empty_project) }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
+ let(:client) { described_class.new(project.repository) }
+
+ describe '#exists?' do
+ it 'sends an exists message' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:exists)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_call_original
+
+ client.exists?
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index ce7b18b784a..921e786a55c 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
# We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want
# those stubs while testing the GitalyClient itself.
-describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
+describe Gitlab::GitalyClient, skip_gitaly_mock: true do
describe '.stub' do
# Notice that this is referring to gRPC "stubs", not rspec stubs
before do
@@ -16,9 +16,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
'default' => { 'gitaly_address' => address }
})
- expect(Gitaly::Commit::Stub).to receive(:new).with(address, any_args)
+ expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args)
- described_class.stub(:commit, 'default')
+ described_class.stub(:commit_service, 'default')
end
end
@@ -31,9 +31,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
'default' => { 'gitaly_address' => prefixed_address }
})
- expect(Gitaly::Commit::Stub).to receive(:new).with(address, any_args)
+ expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args)
- described_class.stub(:commit, 'default')
+ described_class.stub(:commit_service, 'default')
end
end
end
diff --git a/spec/lib/gitlab/github_import/branch_formatter_spec.rb b/spec/lib/gitlab/github_import/branch_formatter_spec.rb
index 3a31f93efa5..426b43f8b51 100644
--- a/spec/lib/gitlab/github_import/branch_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/branch_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::BranchFormatter, lib: true do
+describe Gitlab::GithubImport::BranchFormatter do
let(:project) { create(:project, :repository) }
let(:commit) { create(:commit, project: project) }
let(:repo) { double }
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb
index 21f2a9e225b..66273255b6f 100644
--- a/spec/lib/gitlab/github_import/client_spec.rb
+++ b/spec/lib/gitlab/github_import/client_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::Client, lib: true do
+describe Gitlab::GithubImport::Client do
let(:token) { '123456' }
let(:github_provider) { Settingslogic.new('app_id' => 'asd123', 'app_secret' => 'asd123', 'name' => 'github', 'args' => { 'client_options' => {} }) }
diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
index cc38872e426..ef89634685a 100644
--- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::CommentFormatter, lib: true do
+describe Gitlab::GithubImport::CommentFormatter do
let(:client) { double }
let(:project) { create(:empty_project) }
let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb
index 9d5e20841b5..d00a2deaf7b 100644
--- a/spec/lib/gitlab/github_import/importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::Importer, lib: true do
+describe Gitlab::GithubImport::Importer do
shared_examples 'Gitlab::GithubImport::Importer#execute' do
let(:expected_not_called) { [] }
diff --git a/spec/lib/gitlab/github_import/issuable_formatter_spec.rb b/spec/lib/gitlab/github_import/issuable_formatter_spec.rb
index 6bc5f98ed2c..05294d227bd 100644
--- a/spec/lib/gitlab/github_import/issuable_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/issuable_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::IssuableFormatter, lib: true do
+describe Gitlab::GithubImport::IssuableFormatter do
let(:raw_data) do
double(number: 42)
end
diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
index a4089592cf2..39b15926193 100644
--- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::IssueFormatter, lib: true do
+describe Gitlab::GithubImport::IssueFormatter do
let(:client) { double }
let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb
index 565435824fd..2cc7ac0b446 100644
--- a/spec/lib/gitlab/github_import/label_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::LabelFormatter, lib: true do
+describe Gitlab::GithubImport::LabelFormatter do
let(:project) { create(:empty_project) }
let(:raw) { double(name: 'improvements', color: 'e6e6e6') }
diff --git a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb
index 6d38041c468..310e0536fd7 100644
--- a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::MilestoneFormatter, lib: true do
+describe Gitlab::GithubImport::MilestoneFormatter do
let(:project) { create(:empty_project) }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
diff --git a/spec/lib/gitlab/github_import/project_creator_spec.rb b/spec/lib/gitlab/github_import/project_creator_spec.rb
index a73b1f4ff5d..948e7469a18 100644
--- a/spec/lib/gitlab/github_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/github_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::ProjectCreator, lib: true do
+describe Gitlab::GithubImport::ProjectCreator do
let(:user) { create(:user) }
let(:namespace) { create(:group, owner: user) }
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index b7c59918a76..2e42f6239b7 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
+describe Gitlab::GithubImport::PullRequestFormatter do
let(:client) { double }
let(:project) { create(:project, :repository) }
let(:source_sha) { create(:commit, project: project).id }
diff --git a/spec/lib/gitlab/github_import/release_formatter_spec.rb b/spec/lib/gitlab/github_import/release_formatter_spec.rb
index 13b15e669ab..1357cb636ae 100644
--- a/spec/lib/gitlab/github_import/release_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/release_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::ReleaseFormatter, lib: true do
+describe Gitlab::GithubImport::ReleaseFormatter do
let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
diff --git a/spec/lib/gitlab/github_import/user_formatter_spec.rb b/spec/lib/gitlab/github_import/user_formatter_spec.rb
index db792233657..98e3a7c28b9 100644
--- a/spec/lib/gitlab/github_import/user_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/user_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::UserFormatter, lib: true do
+describe Gitlab::GithubImport::UserFormatter do
let(:client) { double }
let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
diff --git a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb
index 1bd29b8a563..de50265bc14 100644
--- a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::WikiFormatter, lib: true do
+describe Gitlab::GithubImport::WikiFormatter do
let(:project) do
create(:project,
namespace: create(:namespace, path: 'gitlabhq'),
diff --git a/spec/lib/gitlab/gitlab_import/client_spec.rb b/spec/lib/gitlab/gitlab_import/client_spec.rb
index cd8e805466a..50e8d7183ce 100644
--- a/spec/lib/gitlab/gitlab_import/client_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/client_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe Gitlab::GitlabImport::Client, lib: true do
+describe Gitlab::GitlabImport::Client do
include ImportSpecHelper
let(:token) { '123456' }
- let(:client) { Gitlab::GitlabImport::Client.new(token) }
+ let(:client) { described_class.new(token) }
before do
stub_omniauth_provider('gitlab')
diff --git a/spec/lib/gitlab/gitlab_import/importer_spec.rb b/spec/lib/gitlab/gitlab_import/importer_spec.rb
index 4f588da0a83..16b14474b89 100644
--- a/spec/lib/gitlab/gitlab_import/importer_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/importer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitlabImport::Importer, lib: true do
+describe Gitlab::GitlabImport::Importer do
include ImportSpecHelper
describe '#execute' do
diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
index 483f65cd053..da48d8f0670 100644
--- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitlabImport::ProjectCreator, lib: true do
+describe Gitlab::GitlabImport::ProjectCreator do
let(:user) { create(:user) }
let(:repo) do
{
@@ -23,7 +23,7 @@ describe Gitlab::GitlabImport::ProjectCreator, lib: true do
it 'creates project' do
allow_any_instance_of(Project).to receive(:add_import_job)
- project_creator = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, user, access_params)
+ project_creator = described_class.new(repo, namespace, user, access_params)
project = project_creator.execute
expect(project.import_url).to eq("https://oauth2:asdffg@gitlab.com/asd/vim.git")
diff --git a/spec/lib/gitlab/google_code_import/client_spec.rb b/spec/lib/gitlab/google_code_import/client_spec.rb
index 85949ae8dc4..37985c062b4 100644
--- a/spec/lib/gitlab/google_code_import/client_spec.rb
+++ b/spec/lib/gitlab/google_code_import/client_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::GoogleCodeImport::Client, lib: true do
+describe Gitlab::GoogleCodeImport::Client do
let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) }
subject { described_class.new(raw_data) }
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 622a0f513f4..85f40825005 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::GoogleCodeImport::Importer, lib: true do
+describe Gitlab::GoogleCodeImport::Importer do
let(:mapped_user) { create(:user, username: "thilo123") }
let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) }
let(:client) { Gitlab::GoogleCodeImport::Client.new(raw_data) }
diff --git a/spec/lib/gitlab/google_code_import/project_creator_spec.rb b/spec/lib/gitlab/google_code_import/project_creator_spec.rb
index 499a896ee76..aad53938d52 100644
--- a/spec/lib/gitlab/google_code_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/google_code_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GoogleCodeImport::ProjectCreator, lib: true do
+describe Gitlab::GoogleCodeImport::ProjectCreator do
let(:user) { create(:user) }
let(:repo) do
Gitlab::GoogleCodeImport::Repository.new(
@@ -18,7 +18,7 @@ describe Gitlab::GoogleCodeImport::ProjectCreator, lib: true do
it 'creates project' do
allow_any_instance_of(Project).to receive(:add_import_job)
- project_creator = Gitlab::GoogleCodeImport::ProjectCreator.new(repo, namespace, user)
+ project_creator = described_class.new(repo, namespace, user)
project = project_creator.execute
expect(project.import_url).to eq("https://vim.googlecode.com/git/")
diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb
new file mode 100644
index 00000000000..ddb8dd9f0f4
--- /dev/null
+++ b/spec/lib/gitlab/gpg/commit_spec.rb
@@ -0,0 +1,127 @@
+require 'rails_helper'
+
+RSpec.describe Gitlab::Gpg::Commit do
+ describe '#signature' do
+ let!(:project) { create :project, :repository, path: 'sample-project' }
+ let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' }
+
+ context 'unisgned commit' do
+ it 'returns nil' do
+ expect(described_class.new(project.commit).signature).to be_nil
+ end
+ end
+
+ context 'known and verified public key' do
+ let!(:gpg_key) do
+ create :gpg_key, key: GpgHelpers::User1.public_key, user: create(:user, email: GpgHelpers::User1.emails.first)
+ end
+
+ let!(:commit) do
+ raw_commit = double(:raw_commit, signature: [
+ GpgHelpers::User1.signed_commit_signature,
+ GpgHelpers::User1.signed_commit_base_data
+ ], sha: commit_sha)
+ allow(raw_commit).to receive :save!
+
+ create :commit, git_commit: raw_commit, project: project
+ end
+
+ it 'returns a valid signature' do
+ expect(described_class.new(commit).signature).to have_attributes(
+ commit_sha: commit_sha,
+ project: project,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ gpg_key_user_name: GpgHelpers::User1.names.first,
+ gpg_key_user_email: GpgHelpers::User1.emails.first,
+ valid_signature: true
+ )
+ end
+
+ it 'returns the cached signature on second call' do
+ gpg_commit = described_class.new(commit)
+
+ expect(gpg_commit).to receive(:using_keychain).and_call_original
+ gpg_commit.signature
+
+ # consecutive call
+ expect(gpg_commit).not_to receive(:using_keychain).and_call_original
+ gpg_commit.signature
+ end
+ end
+
+ context 'known but unverified public key' do
+ let!(:gpg_key) { create :gpg_key, key: GpgHelpers::User1.public_key }
+
+ let!(:commit) do
+ raw_commit = double(:raw_commit, signature: [
+ GpgHelpers::User1.signed_commit_signature,
+ GpgHelpers::User1.signed_commit_base_data
+ ], sha: commit_sha)
+ allow(raw_commit).to receive :save!
+
+ create :commit, git_commit: raw_commit, project: project
+ end
+
+ it 'returns an invalid signature' do
+ expect(described_class.new(commit).signature).to have_attributes(
+ commit_sha: commit_sha,
+ project: project,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ gpg_key_user_name: GpgHelpers::User1.names.first,
+ gpg_key_user_email: GpgHelpers::User1.emails.first,
+ valid_signature: false
+ )
+ end
+
+ it 'returns the cached signature on second call' do
+ gpg_commit = described_class.new(commit)
+
+ expect(gpg_commit).to receive(:using_keychain).and_call_original
+ gpg_commit.signature
+
+ # consecutive call
+ expect(gpg_commit).not_to receive(:using_keychain).and_call_original
+ gpg_commit.signature
+ end
+ end
+
+ context 'unknown public key' do
+ let!(:commit) do
+ raw_commit = double(:raw_commit, signature: [
+ GpgHelpers::User1.signed_commit_signature,
+ GpgHelpers::User1.signed_commit_base_data
+ ], sha: commit_sha)
+ allow(raw_commit).to receive :save!
+
+ create :commit,
+ git_commit: raw_commit,
+ project: project
+ end
+
+ it 'returns an invalid signature' do
+ expect(described_class.new(commit).signature).to have_attributes(
+ commit_sha: commit_sha,
+ project: project,
+ gpg_key: nil,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ gpg_key_user_name: nil,
+ gpg_key_user_email: nil,
+ valid_signature: false
+ )
+ end
+
+ it 'returns the cached signature on second call' do
+ gpg_commit = described_class.new(commit)
+
+ expect(gpg_commit).to receive(:using_keychain).and_call_original
+ gpg_commit.signature
+
+ # consecutive call
+ expect(gpg_commit).not_to receive(:using_keychain).and_call_original
+ gpg_commit.signature
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
new file mode 100644
index 00000000000..c4e04ee46a2
--- /dev/null
+++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb
@@ -0,0 +1,173 @@
+require 'rails_helper'
+
+RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do
+ describe '#run' do
+ let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' }
+ let!(:project) { create :project, :repository, path: 'sample-project' }
+ let!(:raw_commit) do
+ raw_commit = double(:raw_commit, signature: [
+ GpgHelpers::User1.signed_commit_signature,
+ GpgHelpers::User1.signed_commit_base_data
+ ], sha: commit_sha)
+
+ allow(raw_commit).to receive :save!
+
+ raw_commit
+ end
+
+ let!(:commit) do
+ create :commit, git_commit: raw_commit, project: project
+ end
+
+ before do
+ allow_any_instance_of(Project).to receive(:commit).and_return(commit)
+ end
+
+ context 'gpg signature did have an associated gpg key which was removed later' do
+ let!(:user) { create :user, email: GpgHelpers::User1.emails.first }
+
+ let!(:valid_gpg_signature) do
+ create :gpg_signature,
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: nil,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: true
+ end
+
+ it 'assigns the gpg key to the signature when the missing gpg key is added' do
+ # InvalidGpgSignatureUpdater is called by the after_create hook
+ gpg_key = create :gpg_key,
+ key: GpgHelpers::User1.public_key,
+ user: user
+
+ expect(valid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: true
+ )
+ end
+
+ it 'does not assign the gpg key when an unrelated gpg key is added' do
+ # InvalidGpgSignatureUpdater is called by the after_create hook
+ create :gpg_key,
+ key: GpgHelpers::User2.public_key,
+ user: user
+
+ expect(valid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: nil,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: true
+ )
+ end
+ end
+
+ context 'gpg signature did not have an associated gpg key' do
+ let!(:user) { create :user, email: GpgHelpers::User1.emails.first }
+
+ let!(:invalid_gpg_signature) do
+ create :gpg_signature,
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: nil,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: false
+ end
+
+ it 'updates the signature to being valid when the missing gpg key is added' do
+ # InvalidGpgSignatureUpdater is called by the after_create hook
+ gpg_key = create :gpg_key,
+ key: GpgHelpers::User1.public_key,
+ user: user
+
+ expect(invalid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: true
+ )
+ end
+
+ it 'keeps the signature at being invalid when an unrelated gpg key is added' do
+ # InvalidGpgSignatureUpdater is called by the after_create hook
+ create :gpg_key,
+ key: GpgHelpers::User2.public_key,
+ user: user
+
+ expect(invalid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: nil,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: false
+ )
+ end
+ end
+
+ context 'gpg signature did have an associated unverified gpg key' do
+ let!(:user) do
+ create(:user, email: 'unrelated@example.com').tap do |user|
+ user.skip_reconfirmation!
+ end
+ end
+
+ let!(:invalid_gpg_signature) do
+ create :gpg_signature,
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: nil,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: false
+ end
+
+ it 'updates the signature to being valid when the user updates the email address' do
+ gpg_key = create :gpg_key,
+ key: GpgHelpers::User1.public_key,
+ user: user
+
+ expect(invalid_gpg_signature.reload.valid_signature).to be_falsey
+
+ # InvalidGpgSignatureUpdater is called by the after_update hook
+ user.update_attributes!(email: GpgHelpers::User1.emails.first)
+
+ expect(invalid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: true
+ )
+ end
+
+ it 'keeps the signature at being invalid when the changed email address is still unrelated' do
+ gpg_key = create :gpg_key,
+ key: GpgHelpers::User1.public_key,
+ user: user
+
+ expect(invalid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: false
+ )
+
+ # InvalidGpgSignatureUpdater is called by the after_update hook
+ user.update_attributes!(email: 'still.unrelated@example.com')
+
+ expect(invalid_gpg_signature.reload).to have_attributes(
+ project: project,
+ commit_sha: commit_sha,
+ gpg_key: gpg_key,
+ gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid,
+ valid_signature: false
+ )
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb
new file mode 100644
index 00000000000..8041518117d
--- /dev/null
+++ b/spec/lib/gitlab/gpg_spec.rb
@@ -0,0 +1,83 @@
+require 'rails_helper'
+
+describe Gitlab::Gpg do
+ describe '.fingerprints_from_key' do
+ before do
+ # make sure that each method is using the temporary keychain
+ expect(described_class).to receive(:using_tmp_keychain).and_call_original
+ end
+
+ it 'returns CurrentKeyChain.fingerprints_from_key' do
+ expect(Gitlab::Gpg::CurrentKeyChain).to receive(:fingerprints_from_key).with(GpgHelpers::User1.public_key)
+
+ described_class.fingerprints_from_key(GpgHelpers::User1.public_key)
+ end
+ end
+
+ describe '.primary_keyids_from_key' do
+ it 'returns the keyid' do
+ expect(
+ described_class.primary_keyids_from_key(GpgHelpers::User1.public_key)
+ ).to eq [GpgHelpers::User1.primary_keyid]
+ end
+
+ it 'returns an empty array when the key is invalid' do
+ expect(
+ described_class.primary_keyids_from_key('bogus')
+ ).to eq []
+ end
+ end
+
+ describe '.user_infos_from_key' do
+ it 'returns the names and emails' do
+ user_infos = described_class.user_infos_from_key(GpgHelpers::User1.public_key)
+ expect(user_infos).to eq([{
+ name: GpgHelpers::User1.names.first,
+ email: GpgHelpers::User1.emails.first
+ }])
+ end
+
+ it 'returns an empty array when the key is invalid' do
+ expect(
+ described_class.user_infos_from_key('bogus')
+ ).to eq []
+ end
+ end
+end
+
+describe Gitlab::Gpg::CurrentKeyChain do
+ around do |example|
+ Gitlab::Gpg.using_tmp_keychain do
+ example.run
+ end
+ end
+
+ describe '.add' do
+ it 'stores the key in the keychain' do
+ expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq []
+
+ described_class.add(GpgHelpers::User1.public_key)
+
+ keys = GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)
+ expect(keys.count).to eq 1
+ expect(keys.first).to have_attributes(
+ email: GpgHelpers::User1.emails.first,
+ fingerprint: GpgHelpers::User1.fingerprint
+ )
+ end
+ end
+
+ describe '.fingerprints_from_key' do
+ it 'returns the fingerprint' do
+ expect(
+ described_class.fingerprints_from_key(GpgHelpers::User1.public_key)
+ ).to eq [GpgHelpers::User1.fingerprint]
+ end
+
+ it 'returns an empty array when the key is invalid' do
+ expect(
+ described_class.fingerprints_from_key('bogus')
+ ).to eq []
+ end
+ end
+end
diff --git a/spec/lib/gitlab/graphs/commits_spec.rb b/spec/lib/gitlab/graphs/commits_spec.rb
index abb5a26060f..3f9382a9143 100644
--- a/spec/lib/gitlab/graphs/commits_spec.rb
+++ b/spec/lib/gitlab/graphs/commits_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Graphs::Commits, lib: true do
+describe Gitlab::Graphs::Commits do
let!(:project) { create(:empty_project, :public) }
let!(:commit1) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: Time.now) }
diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb
index 61c10d47434..8abc4320c59 100644
--- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb
+++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::HealthChecks::FsShardsCheck do
def command_exists?(command)
_, status = Gitlab::Popen.popen(%W{ #{command} 1 echo })
- status == 0
+ status.zero?
rescue Errno::ENOENT
false
end
@@ -64,9 +64,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do
it 'cleans up files used for testing' do
expect(described_class).to receive(:storage_write_test).with(any_args).and_call_original
- subject
-
- expect(Dir.entries(tmp_dir).count).to eq(2)
+ expect { subject }.not_to change(Dir.entries(tmp_dir), :count)
end
context 'read test fails' do
@@ -88,8 +86,6 @@ describe Gitlab::HealthChecks::FsShardsCheck do
end
describe '#metrics' do
- subject { described_class.metrics }
-
context 'storage points to not existing folder' do
let(:storages_paths) do
{
@@ -97,30 +93,45 @@ describe Gitlab::HealthChecks::FsShardsCheck do
}.with_indifferent_access
end
- it { is_expected.to all(have_attributes(labels: { shard: :default })) }
+ # Unsolved intermittent failure in CI https://gitlab.com/gitlab-org/gitlab-ce/issues/31128
+ around(:each) do |example| # rubocop:disable RSpec/AroundBlock
+ times_to_try = ENV['CI'] ? 4 : 1
+ example.run_with_retry retry: times_to_try
+ end
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) }
+ it 'provides metrics' do
+ metrics = described_class.metrics
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_access_latency, value: be >= 0)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_read_latency, value: be >= 0)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_write_latency, value: be >= 0)) }
+ expect(metrics).to all(have_attributes(labels: { shard: :default }))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0))
+ end
end
context 'storage points to directory that has both read and write rights' do
before do
FileUtils.chmod_R(0755, tmp_dir)
end
- it { is_expected.to all(have_attributes(labels: { shard: :default })) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_accessible, value: 1)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_readable, value: 1)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_writable, value: 1)) }
+ it 'provides metrics' do
+ metrics = described_class.metrics
+
+ expect(metrics).to all(have_attributes(labels: { shard: :default }))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 1))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 1))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 1))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0))
+ end
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_access_latency, value: be >= 0)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_read_latency, value: be >= 0)) }
- it { is_expected.to include(an_object_having_attributes(name: :filesystem_write_latency, value: be >= 0)) }
+ it 'cleans up files used for metrics' do
+ expect { described_class.metrics }.not_to change(Dir.entries(tmp_dir), :count)
+ end
end
end
end
@@ -140,18 +151,16 @@ describe Gitlab::HealthChecks::FsShardsCheck do
end
describe '#metrics' do
- subject { described_class.metrics }
-
it 'provides metrics' do
- expect(subject).to all(have_attributes(labels: { shard: :default }))
-
- expect(subject).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0))
- expect(subject).to include(an_object_having_attributes(name: :filesystem_readable, value: 0))
- expect(subject).to include(an_object_having_attributes(name: :filesystem_writable, value: 0))
-
- expect(subject).to include(an_object_having_attributes(name: :filesystem_access_latency, value: be >= 0))
- expect(subject).to include(an_object_having_attributes(name: :filesystem_read_latency, value: be >= 0))
- expect(subject).to include(an_object_having_attributes(name: :filesystem_write_latency, value: be >= 0))
+ metrics = described_class.metrics
+
+ expect(metrics).to all(have_attributes(labels: { shard: :default }))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0))
+ expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0))
end
end
end
diff --git a/spec/lib/gitlab/health_checks/redis/cache_check_spec.rb b/spec/lib/gitlab/health_checks/redis/cache_check_spec.rb
new file mode 100644
index 00000000000..3693f52b51b
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/redis/cache_check_spec.rb
@@ -0,0 +1,6 @@
+require 'spec_helper'
+require_relative '../simple_check_shared'
+
+describe Gitlab::HealthChecks::Redis::CacheCheck do
+ include_examples 'simple_check', 'redis_cache_ping', 'RedisCache', 'PONG'
+end
diff --git a/spec/lib/gitlab/health_checks/redis/queues_check_spec.rb b/spec/lib/gitlab/health_checks/redis/queues_check_spec.rb
new file mode 100644
index 00000000000..c69443d205d
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/redis/queues_check_spec.rb
@@ -0,0 +1,6 @@
+require 'spec_helper'
+require_relative '../simple_check_shared'
+
+describe Gitlab::HealthChecks::Redis::QueuesCheck do
+ include_examples 'simple_check', 'redis_queues_ping', 'RedisQueues', 'PONG'
+end
diff --git a/spec/lib/gitlab/health_checks/redis/redis_check_spec.rb b/spec/lib/gitlab/health_checks/redis/redis_check_spec.rb
new file mode 100644
index 00000000000..03afc1cd761
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/redis/redis_check_spec.rb
@@ -0,0 +1,6 @@
+require 'spec_helper'
+require_relative '../simple_check_shared'
+
+describe Gitlab::HealthChecks::Redis::RedisCheck do
+ include_examples 'simple_check', 'redis_ping', 'Redis', 'PONG'
+end
diff --git a/spec/lib/gitlab/health_checks/redis/shared_state_check_spec.rb b/spec/lib/gitlab/health_checks/redis/shared_state_check_spec.rb
new file mode 100644
index 00000000000..b72e152bbe2
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/redis/shared_state_check_spec.rb
@@ -0,0 +1,6 @@
+require 'spec_helper'
+require_relative '../simple_check_shared'
+
+describe Gitlab::HealthChecks::Redis::SharedStateCheck do
+ include_examples 'simple_check', 'redis_shared_state_ping', 'RedisSharedState', 'PONG'
+end
diff --git a/spec/lib/gitlab/health_checks/redis_check_spec.rb b/spec/lib/gitlab/health_checks/redis_check_spec.rb
deleted file mode 100644
index 734cdcb893e..00000000000
--- a/spec/lib/gitlab/health_checks/redis_check_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require 'spec_helper'
-require_relative './simple_check_shared'
-
-describe Gitlab::HealthChecks::RedisCheck do
- include_examples 'simple_check', 'redis_ping', 'Redis', 'PONG'
-end
diff --git a/spec/lib/gitlab/health_checks/simple_check_shared.rb b/spec/lib/gitlab/health_checks/simple_check_shared.rb
index 3f871d66034..e2643458aca 100644
--- a/spec/lib/gitlab/health_checks/simple_check_shared.rb
+++ b/spec/lib/gitlab/health_checks/simple_check_shared.rb
@@ -8,7 +8,7 @@ shared_context 'simple_check' do |metrics_prefix, check_name, success_result|
it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_success", value: 1)) }
it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_timeout", value: 0)) }
- it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_latency", value: be >= 0)) }
+ it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_latency_seconds", value: be >= 0)) }
end
context 'Check is misbehaving' do
@@ -18,7 +18,7 @@ shared_context 'simple_check' do |metrics_prefix, check_name, success_result|
it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_success", value: 0)) }
it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_timeout", value: 0)) }
- it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_latency", value: be >= 0)) }
+ it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_latency_seconds", value: be >= 0)) }
end
context 'Check is timeouting' do
@@ -28,7 +28,7 @@ shared_context 'simple_check' do |metrics_prefix, check_name, success_result|
it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_success", value: 0)) }
it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_timeout", value: 1)) }
- it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_latency", value: be >= 0)) }
+ it { is_expected.to include(have_attributes(name: "#{metrics_prefix}_latency_seconds", value: be >= 0)) }
end
end
@@ -47,7 +47,7 @@ shared_context 'simple_check' do |metrics_prefix, check_name, success_result|
allow(described_class).to receive(:check).and_return 'error!'
end
- it { is_expected.to have_attributes(success: false, message: "unexpected #{check_name} check result: error!") }
+ it { is_expected.to have_attributes(success: false, message: "unexpected #{described_class.human_name} check result: error!") }
end
context 'Check is timeouting' do
@@ -55,7 +55,7 @@ shared_context 'simple_check' do |metrics_prefix, check_name, success_result|
allow(described_class).to receive(:check ).and_return Timeout::Error.new
end
- it { is_expected.to have_attributes(success: false, message: "#{check_name} check timed out") }
+ it { is_expected.to have_attributes(success: false, message: "#{described_class.human_name} check timed out") }
end
end
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index 07687b470c5..29e61d15726 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Highlight, lib: true do
+describe Gitlab::Highlight do
include RepoHelpers
let(:project) { create(:project, :repository) }
@@ -12,7 +12,7 @@ describe Gitlab::Highlight, lib: true do
let(:blob) { repository.blob_at_branch(branch, path) }
let(:highlighter) do
- Gitlab::Highlight.new(blob.path, blob.data, repository: repository)
+ described_class.new(blob.path, blob.data, repository: repository)
end
before do
@@ -42,7 +42,7 @@ describe Gitlab::Highlight, lib: true do
let(:path) { 'files/whitespace' }
let(:blob) { repository.blob_at_branch(branch, path) }
let(:lines) do
- Gitlab::Highlight.highlight(blob.path, blob.data, repository: repository).lines
+ described_class.highlight(blob.path, blob.data, repository: repository).lines
end
it 'strips extra LFs' do
diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb
index 0dba4132101..785035d993f 100644
--- a/spec/lib/gitlab/i18n_spec.rb
+++ b/spec/lib/gitlab/i18n_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::I18n, lib: true do
+describe Gitlab::I18n do
let(:user) { create(:user, preferred_language: 'es') }
describe '.locale=' do
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index a5f09f1856e..6a41afe0c25 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -45,6 +45,7 @@ label:
- merge_requests
- priorities
milestone:
+- group
- project
- issues
- labels
@@ -88,7 +89,10 @@ merge_requests:
- head_pipeline
merge_request_diff:
- merge_request
+- merge_request_diff_commits
- merge_request_diff_files
+merge_request_diff_commits:
+- merge_request_diff
merge_request_diff_files:
- merge_request_diff
pipelines:
@@ -98,6 +102,7 @@ pipelines:
- statuses
- builds
- trigger_requests
+- variables
- auto_canceled_by
- auto_canceled_pipelines
- auto_canceled_jobs
@@ -108,6 +113,8 @@ pipelines:
- artifacts
- pipeline_schedule
- merge_requests
+pipeline_variables:
+- pipeline
stages:
- project
- pipeline
@@ -130,8 +137,11 @@ pipeline_schedules:
- owner
- pipelines
- last_pipeline
+- variables
pipeline_schedule:
- pipelines
+pipeline_schedule_variables:
+- pipeline_schedule
deploy_keys:
- user
- deploy_keys_projects
diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
index 63bab0f0d0d..574748756bd 100644
--- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
+++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::AttributeCleaner, lib: true do
+describe Gitlab::ImportExport::AttributeCleaner do
let(:relation_class){ double('relation_class').as_null_object }
let(:unsafe_hash) do
{
diff --git a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
index e24d070706a..65f073b2df3 100644
--- a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
@@ -7,7 +7,7 @@ require 'spec_helper'
# to be included as part of the export, or blacklist them using the import_export.yml configuration file.
# Likewise, new models added to import_export.yml, will need to be added with their correspondent attributes
# to this spec.
-describe 'Import/Export attribute configuration', lib: true do
+describe 'Import/Export attribute configuration' do
include ConfigurationHelper
let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys }
diff --git a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
index 08a42fd27a2..a7b292c8558 100644
--- a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::AvatarRestorer, lib: true do
+describe Gitlab::ImportExport::AvatarRestorer do
include UploadHelpers
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
index 579a31ead58..814f85de03b 100644
--- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::AvatarSaver, lib: true do
+describe Gitlab::ImportExport::AvatarSaver do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:project_with_avatar) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb
index b88b9c18c15..690c7625c52 100644
--- a/spec/lib/gitlab/import_export/file_importer_spec.rb
+++ b/spec/lib/gitlab/import_export/file_importer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::FileImporter, lib: true do
+describe Gitlab::ImportExport::FileImporter do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
let(:export_path) { "#{Dir.tmpdir}/file_importer_spec" }
let(:valid_file) { "#{shared.export_path}/valid.json" }
diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb
index 42f3fc59f04..08588a76fe6 100644
--- a/spec/lib/gitlab/import_export/fork_spec.rb
+++ b/spec/lib/gitlab/import_export/fork_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe 'forked project import', services: true do
+describe 'forked project import' do
let(:user) { create(:user) }
- let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') }
+ let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
@@ -44,6 +44,8 @@ describe 'forked project import', services: true do
end
it 'can access the MR' do
- expect(project.merge_requests.first.ensure_ref_fetched.first).to include('refs/merge-requests/1/head')
+ project.merge_requests.first.ensure_ref_fetched
+
+ expect(project.repository.ref_exists?('refs/merge-requests/1/head')).to be_truthy
end
end
diff --git a/spec/lib/gitlab/import_export/hash_util_spec.rb b/spec/lib/gitlab/import_export/hash_util_spec.rb
index 1c3a0b23ece..366582dece3 100644
--- a/spec/lib/gitlab/import_export/hash_util_spec.rb
+++ b/spec/lib/gitlab/import_export/hash_util_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::HashUtil, lib: true do
+describe Gitlab::ImportExport::HashUtil do
let(:stringified_array) { [{ 'test' => 1 }] }
let(:stringified_array_with_date) { [{ 'test_date' => '2016-04-06 06:17:44 +0200' }] }
diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb
index f3fd0d82875..07415d41f93 100644
--- a/spec/lib/gitlab/import_export/import_export_spec.rb
+++ b/spec/lib/gitlab/import_export/import_export_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport, services: true do
+describe Gitlab::ImportExport do
describe 'export filename' do
let(:group) { create(:group, :nested) }
let(:project) { create(:empty_project, :public, path: 'project-path', namespace: group) }
diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb
index 3e0291c9ae9..f66a2ab7dda 100644
--- a/spec/lib/gitlab/import_export/members_mapper_spec.rb
+++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::MembersMapper, services: true do
+describe Gitlab::ImportExport::MembersMapper do
describe 'map members' do
let(:user) { create(:admin) }
let(:project) { create(:empty_project, :public, name: 'searchable_project') }
diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
index 349be4596b6..f2b66c4421c 100644
--- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
+++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::MergeRequestParser do
let(:user) { create(:user) }
- let!(:project) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') }
+ let!(:project) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let(:forked_from_project) { create(:project) }
let(:fork_link) { create(:forked_project_link, forked_from_project: project) }
diff --git a/spec/lib/gitlab/import_export/model_configuration_spec.rb b/spec/lib/gitlab/import_export/model_configuration_spec.rb
index 2ede5cdd2ad..5cb8f2589c8 100644
--- a/spec/lib/gitlab/import_export/model_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/model_configuration_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
# Part of the test security suite for the Import/Export feature
# Finds if a new model has been added that can potentially be part of the Import/Export
# If it finds a new model, it will show a +failure_message+ with the options available.
-describe 'Import/Export model configuration', lib: true do
+describe 'Import/Export model configuration' do
include ConfigurationHelper
let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys }
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 98c117b4cd8..469a014e4d2 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2741,13 +2741,12 @@
"merge_request_diff": {
"id": 27,
"state": "collected",
- "st_commits": [
+ "merge_request_diff_commits": [
{
- "id": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc",
+ "merge_request_diff_id": 27,
+ "relative_order": 0,
+ "sha": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc",
"message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
- "parent_ids": [
- "5937ac0a7beb003549fc5fd26fc247adbce4a52e"
- ],
"authored_date": "2014-08-06T08:35:52.000+02:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2756,11 +2755,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
},
{
- "id": "5937ac0a7beb003549fc5fd26fc247adbce4a52e",
+ "merge_request_diff_id": 27,
+ "relative_order": 1,
+ "sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e",
"message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
- "parent_ids": [
- "570e7b2abdd848b95f2f578043fc23bd6f6fd24d"
- ],
"authored_date": "2014-02-27T10:01:38.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2769,11 +2767,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
},
{
- "id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
+ "merge_request_diff_id": 27,
+ "relative_order": 2,
+ "sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
"message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
- "parent_ids": [
- "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9"
- ],
"authored_date": "2014-02-27T09:57:31.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2782,11 +2779,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
},
{
- "id": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
+ "merge_request_diff_id": 27,
+ "relative_order": 3,
+ "sha": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
"message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
- "parent_ids": [
- "d14d6c0abdd253381df51a723d58691b2ee1ab08"
- ],
"authored_date": "2014-02-27T09:54:21.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2795,11 +2791,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
},
{
- "id": "d14d6c0abdd253381df51a723d58691b2ee1ab08",
+ "merge_request_diff_id": 27,
+ "relative_order": 4,
+ "sha": "d14d6c0abdd253381df51a723d58691b2ee1ab08",
"message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
- "parent_ids": [
- "c1acaa58bbcbc3eafe538cb8274ba387047b69f8"
- ],
"authored_date": "2014-02-27T09:49:50.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
@@ -2808,11 +2803,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com"
},
{
- "id": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
+ "merge_request_diff_id": 27,
+ "relative_order": 5,
+ "sha": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
"message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
- "parent_ids": [
- "ae73cb07c9eeaf35924a10f713b364d32b2dd34f"
- ],
"authored_date": "2014-02-27T09:48:32.000+01:00",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com",
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index c11b15a811b..d1ec0e45bbd 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
include ImportExport::CommonUtil
-describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
+describe Gitlab::ImportExport::ProjectTreeRestorer do
describe 'restore project tree' do
before(:context) do
@user = create(:user)
@@ -95,6 +95,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(MergeRequestDiffFile.where.not(diff: nil).count).to eq(9)
end
+ it 'has the correct data for merge request diff commits in serialised and table formats' do
+ expect(MergeRequestDiff.where.not(st_commits: nil).count).to eq(7)
+ expect(MergeRequestDiffCommit.count).to eq(6)
+ end
+
it 'has the correct time for merge request st_commits' do
st_commits = MergeRequestDiff.where.not(st_commits: nil).first.st_commits
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index e52f79513f1..0c7e733b01f 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
+describe Gitlab::ImportExport::ProjectTreeSaver do
describe 'saves the project tree into a json object' do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
@@ -87,6 +87,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_files']).not_to be_empty
end
+ it 'has merge request diff commits' do
+ expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_commits']).not_to be_empty
+ end
+
it 'has merge requests comments' do
expect(saved_project_json['merge_requests'].first['notes']).not_to be_empty
end
diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb
index d700af142be..e9f5273725d 100644
--- a/spec/lib/gitlab/import_export/reader_spec.rb
+++ b/spec/lib/gitlab/import_export/reader_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::Reader, lib: true do
+describe Gitlab::ImportExport::Reader do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') }
let(:test_config) { 'spec/support/import_export/import_export.yml' }
let(:project_tree_hash) do
diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb
index 5417c7534ea..baa90af84f7 100644
--- a/spec/lib/gitlab/import_export/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::RelationFactory, lib: true do
+describe Gitlab::ImportExport::RelationFactory do
let(:project) { create(:empty_project) }
let(:members_mapper) { double('members_mapper').as_null_object }
let(:user) { create(:admin) }
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index 168a59e5139..d3be2965bf4 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::ImportExport::RepoRestorer, services: true do
+describe Gitlab::ImportExport::RepoRestorer do
describe 'bundle a project Git repo' do
let(:user) { create(:user) }
- let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') }
+ let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') }
let!(:project) { create(:empty_project) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
@@ -34,7 +34,7 @@ describe Gitlab::ImportExport::RepoRestorer, services: true do
it 'has the webhooks' do
restorer.restore
- expect(Gitlab::Git::Hook.new('post-receive', project.repository.path_to_repo)).to exist
+ expect(Gitlab::Git::Hook.new('post-receive', project)).to exist
end
end
end
diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb
index a7f4e11271e..87af13e0beb 100644
--- a/spec/lib/gitlab/import_export/repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::RepoSaver, services: true do
+describe Gitlab::ImportExport::RepoSaver do
describe 'bundle a project Git repo' do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, :public, name: 'searchable_project') }
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index fadd3ad1330..11f4c16ff96 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -82,6 +82,7 @@ Milestone:
- id
- title
- project_id
+- group_id
- description
- due_date
- start_date
@@ -172,6 +173,17 @@ MergeRequestDiff:
- real_size
- head_commit_sha
- start_commit_sha
+MergeRequestDiffCommit:
+- merge_request_diff_id
+- relative_order
+- sha
+- authored_date
+- committed_date
+- author_name
+- author_email
+- committer_name
+- committer_email
+- message
MergeRequestDiffFile:
- merge_request_diff_id
- relative_order
@@ -183,6 +195,7 @@ MergeRequestDiffFile:
- a_mode
- b_mode
- too_large
+- binary
Ci::Pipeline:
- id
- project_id
@@ -383,6 +396,8 @@ Project:
- printing_merge_request_link_enabled
- build_allow_git_fetch
- last_repository_updated_at
+- ci_config_path
+- delete_error
Author:
- name
ProjectFeature:
diff --git a/spec/lib/gitlab/import_export/version_checker_spec.rb b/spec/lib/gitlab/import_export/version_checker_spec.rb
index 2405ac5abfe..e7d50f75682 100644
--- a/spec/lib/gitlab/import_export/version_checker_spec.rb
+++ b/spec/lib/gitlab/import_export/version_checker_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
include ImportExport::CommonUtil
-describe Gitlab::ImportExport::VersionChecker, services: true do
+describe Gitlab::ImportExport::VersionChecker do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') }
describe 'bundle a project Git repo' do
diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
index 071e5fac3f0..78137aeff5e 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ImportExport::WikiRepoSaver, services: true do
+describe Gitlab::ImportExport::WikiRepoSaver do
describe 'bundle a wiki Git repo' do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, :public, name: 'searchable_project') }
diff --git a/spec/lib/gitlab/incoming_email_spec.rb b/spec/lib/gitlab/incoming_email_spec.rb
index 698bd72d0f8..c959add7a36 100644
--- a/spec/lib/gitlab/incoming_email_spec.rb
+++ b/spec/lib/gitlab/incoming_email_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::IncomingEmail, lib: true do
+describe Gitlab::IncomingEmail do
describe "self.enabled?" do
context "when reply by email is enabled" do
before do
diff --git a/spec/lib/gitlab/issuable_metadata_spec.rb b/spec/lib/gitlab/issuable_metadata_spec.rb
new file mode 100644
index 00000000000..2455969a183
--- /dev/null
+++ b/spec/lib/gitlab/issuable_metadata_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+
+describe Gitlab::IssuableMetadata do
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) }
+
+ subject { Class.new { include Gitlab::IssuableMetadata }.new }
+
+ it 'returns an empty Hash if an empty collection is provided' do
+ expect(subject.issuable_meta_data(Issue.none, 'Issue')).to eq({})
+ end
+
+ context 'issues' do
+ let!(:issue) { create(:issue, author: user, project: project) }
+ let!(:closed_issue) { create(:issue, state: :closed, author: user, project: project) }
+ let!(:downvote) { create(:award_emoji, :downvote, awardable: closed_issue) }
+ let!(:upvote) { create(:award_emoji, :upvote, awardable: issue) }
+ let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test") }
+ let!(:closing_issues) { create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request) }
+
+ it 'aggregates stats on issues' do
+ data = subject.issuable_meta_data(Issue.all, 'Issue')
+
+ expect(data.count).to eq(2)
+ expect(data[issue.id].upvotes).to eq(1)
+ expect(data[issue.id].downvotes).to eq(0)
+ expect(data[issue.id].notes_count).to eq(0)
+ expect(data[issue.id].merge_requests_count).to eq(1)
+
+ expect(data[closed_issue.id].upvotes).to eq(0)
+ expect(data[closed_issue.id].downvotes).to eq(1)
+ expect(data[closed_issue.id].notes_count).to eq(0)
+ expect(data[closed_issue.id].merge_requests_count).to eq(0)
+ end
+ end
+
+ context 'merge requests' do
+ let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test") }
+ let!(:merge_request_closed) { create(:merge_request, state: "closed", source_project: project, target_project: project, title: "Closed Test") }
+ let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request) }
+ let!(:upvote) { create(:award_emoji, :upvote, awardable: merge_request) }
+ let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
+
+ it 'aggregates stats on merge requests' do
+ data = subject.issuable_meta_data(MergeRequest.all, 'MergeRequest')
+
+ expect(data.count).to eq(2)
+ expect(data[merge_request.id].upvotes).to eq(1)
+ expect(data[merge_request.id].downvotes).to eq(1)
+ expect(data[merge_request.id].notes_count).to eq(1)
+ expect(data[merge_request.id].merge_requests_count).to eq(0)
+
+ expect(data[merge_request_closed.id].upvotes).to eq(0)
+ expect(data[merge_request_closed.id].downvotes).to eq(0)
+ expect(data[merge_request_closed.id].notes_count).to eq(0)
+ expect(data[merge_request_closed.id].merge_requests_count).to eq(0)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/issuable_sorter_spec.rb b/spec/lib/gitlab/issuable_sorter_spec.rb
index c9a434b2bcf..aeb32ef96d6 100644
--- a/spec/lib/gitlab/issuable_sorter_spec.rb
+++ b/spec/lib/gitlab/issuable_sorter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::IssuableSorter, lib: true do
+describe Gitlab::IssuableSorter do
let(:namespace1) { build(:namespace, id: 1) }
let(:project1) { build(:project, id: 1, namespace: namespace1) }
diff --git a/spec/lib/gitlab/key_fingerprint_spec.rb b/spec/lib/gitlab/key_fingerprint_spec.rb
index d09f51f3bfc..d7bebaca675 100644
--- a/spec/lib/gitlab/key_fingerprint_spec.rb
+++ b/spec/lib/gitlab/key_fingerprint_spec.rb
@@ -1,12 +1,12 @@
require "spec_helper"
-describe Gitlab::KeyFingerprint, lib: true do
+describe Gitlab::KeyFingerprint do
let(:key) { "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" }
let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" }
describe "#fingerprint" do
it "generates the key's fingerprint" do
- expect(Gitlab::KeyFingerprint.new(key).fingerprint).to eq(fingerprint)
+ expect(described_class.new(key).fingerprint).to eq(fingerprint)
end
end
end
diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb
index e8c599a95ee..34b33772578 100644
--- a/spec/lib/gitlab/kubernetes_spec.rb
+++ b/spec/lib/gitlab/kubernetes_spec.rb
@@ -46,4 +46,28 @@ describe Gitlab::Kubernetes do
expect(filter_by_label(items, app: 'foo')).to eq(matching_items)
end
end
+
+ describe '#to_kubeconfig' do
+ subject do
+ to_kubeconfig(
+ url: 'https://kube.domain.com',
+ namespace: 'NAMESPACE',
+ token: 'TOKEN',
+ ca_pem: ca_pem)
+ end
+
+ context 'when CA PEM is provided' do
+ let(:ca_pem) { 'PEM' }
+ let(:path) { expand_fixture_path('config/kubeconfig.yml') }
+
+ it { is_expected.to eq(YAML.load_file(path)) }
+ end
+
+ context 'when CA PEM is not provided' do
+ let(:ca_pem) { nil }
+ let(:path) { expand_fixture_path('config/kubeconfig-without-ca.yml') }
+
+ it { is_expected.to eq(YAML.load_file(path)) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/lazy_spec.rb b/spec/lib/gitlab/lazy_spec.rb
index b5ca89dd242..37a3ac74316 100644
--- a/spec/lib/gitlab/lazy_spec.rb
+++ b/spec/lib/gitlab/lazy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Lazy, lib: true do
+describe Gitlab::Lazy do
let(:dummy) { double(:dummy) }
context 'when not calling any methods' do
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index 9dd997aa7dc..6a47350be81 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -1,9 +1,19 @@
require 'spec_helper'
-describe Gitlab::LDAP::Access, lib: true do
- let(:access) { Gitlab::LDAP::Access.new user }
+describe Gitlab::LDAP::Access do
+ let(:access) { described_class.new user }
let(:user) { create(:omniauth_user) }
+ describe '.allowed?' do
+ it 'updates the users `last_credential_check_at' do
+ expect(access).to receive(:allowed?) { true }
+ expect(described_class).to receive(:open).and_yield(access)
+
+ expect { described_class.allowed?(user) }
+ .to change { user.last_credential_check_at }
+ end
+ end
+
describe '#allowed?' do
subject { access.allowed? }
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index 9454878b057..d17d440d833 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::Adapter, lib: true do
+describe Gitlab::LDAP::Adapter do
include LdapHelpers
let(:ldap) { double(:ldap) }
@@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter, lib: true do
expect(adapter).to receive(:ldap_search) do |arg|
expect(arg[:filter].to_s).to eq('(uid=johndoe)')
expect(arg[:base]).to eq('dc=example,dc=com')
- expect(arg[:attributes]).to match(%w{uid cn mail dn})
+ expect(arg[:attributes]).to match(%w{uid cn dn uid userid sAMAccountName mail email userPrincipalName})
end.and_return({})
adapter.users('uid', 'johndoe')
@@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter, lib: true do
expect(adapter).to receive(:ldap_search).with(
base: 'uid=johndoe,ou=users,dc=example,dc=com',
scope: Net::LDAP::SearchScope_BaseObject,
- attributes: %w{uid cn mail dn},
+ attributes: %w{uid cn dn uid userid sAMAccountName mail email userPrincipalName},
filter: nil
).and_return({})
@@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter, lib: true do
it 'uses the right uid attribute when non-default' do
stub_ldap_config(uid: 'sAMAccountName')
expect(adapter).to receive(:ldap_search).with(
- hash_including(attributes: %w{sAMAccountName cn mail dn})
+ hash_including(attributes: %w{sAMAccountName cn dn uid userid sAMAccountName mail email userPrincipalName})
).and_return({})
adapter.users('sAMAccountName', 'johndoe')
diff --git a/spec/lib/gitlab/ldap/auth_hash_spec.rb b/spec/lib/gitlab/ldap/auth_hash_spec.rb
index 7a2f774b948..57a91193004 100644
--- a/spec/lib/gitlab/ldap/auth_hash_spec.rb
+++ b/spec/lib/gitlab/ldap/auth_hash_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Gitlab::LDAP::AuthHash, lib: true do
+describe Gitlab::LDAP::AuthHash do
let(:auth_hash) do
- Gitlab::LDAP::AuthHash.new(
+ described_class.new(
OmniAuth::AuthHash.new(
uid: '123456',
provider: 'ldapmain',
diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb
index f689b47fec4..01b6282af0c 100644
--- a/spec/lib/gitlab/ldap/authentication_spec.rb
+++ b/spec/lib/gitlab/ldap/authentication_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::Authentication, lib: true do
+describe Gitlab::LDAP::Authentication do
let(:user) { create(:omniauth_user, extern_uid: dn) }
let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
let(:login) { 'john' }
diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb
index cab2e9908ff..292ec064a67 100644
--- a/spec/lib/gitlab/ldap/config_spec.rb
+++ b/spec/lib/gitlab/ldap/config_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-describe Gitlab::LDAP::Config, lib: true do
+describe Gitlab::LDAP::Config do
include LdapHelpers
- let(:config) { Gitlab::LDAP::Config.new('ldapmain') }
+ let(:config) { described_class.new('ldapmain') }
- describe '#initalize' do
+ describe '#initialize' do
it 'requires a provider' do
- expect{ Gitlab::LDAP::Config.new }.to raise_error ArgumentError
+ expect{ described_class.new }.to raise_error ArgumentError
end
it 'works' do
@@ -15,7 +15,7 @@ describe Gitlab::LDAP::Config, lib: true do
end
it 'raises an error if a unknown provider is used' do
- expect{ Gitlab::LDAP::Config.new 'unknown' }.to raise_error(RuntimeError)
+ expect{ described_class.new 'unknown' }.to raise_error(RuntimeError)
end
end
@@ -23,9 +23,9 @@ describe Gitlab::LDAP::Config, lib: true do
it 'constructs basic options' do
stub_ldap_config(
options: {
- 'host' => 'ldap.example.com',
- 'port' => 386,
- 'method' => 'plain'
+ 'host' => 'ldap.example.com',
+ 'port' => 386,
+ 'encryption' => 'plain'
}
)
@@ -39,24 +39,140 @@ describe Gitlab::LDAP::Config, lib: true do
it 'includes authentication options when auth is configured' do
stub_ldap_config(
options: {
- 'host' => 'ldap.example.com',
- 'port' => 686,
- 'method' => 'ssl',
- 'bind_dn' => 'uid=admin,dc=example,dc=com',
- 'password' => 'super_secret'
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'bind_dn' => 'uid=admin,dc=example,dc=com',
+ 'password' => 'super_secret'
}
)
- expect(config.adapter_options).to eq(
- host: 'ldap.example.com',
- port: 686,
- encryption: :simple_tls,
+ expect(config.adapter_options).to include({
auth: {
method: :simple,
username: 'uid=admin,dc=example,dc=com',
password: 'super_secret'
}
+ })
+ end
+
+ it 'sets encryption method to simple_tls when configured as simple_tls' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls'
+ }
)
+
+ expect(config.adapter_options[:encryption]).to include({ method: :simple_tls })
+ end
+
+ it 'sets encryption method to start_tls when configured as start_tls' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'start_tls'
+ }
+ )
+
+ expect(config.adapter_options[:encryption]).to include({ method: :start_tls })
+ end
+
+ context 'when verify_certificates is enabled' do
+ it 'sets tls_options to OpenSSL defaults' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true
+ }
+ )
+
+ expect(config.adapter_options[:encryption]).to include({ tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS })
+ end
+ end
+
+ context 'when verify_certificates is disabled' do
+ it 'sets verify_mode to OpenSSL VERIFY_NONE' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => false
+ }
+ )
+
+ expect(config.adapter_options[:encryption]).to include({
+ tls_options: {
+ verify_mode: OpenSSL::SSL::VERIFY_NONE
+ }
+ })
+ end
+ end
+
+ context 'when ca_file is specified' do
+ it 'passes it through in tls_options' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'ca_file' => '/etc/ca.pem'
+ }
+ )
+
+ expect(config.adapter_options[:encryption][:tls_options]).to include({ ca_file: '/etc/ca.pem' })
+ end
+ end
+
+ context 'when ca_file is a blank string' do
+ it 'does not add the ca_file key to tls_options' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'ca_file' => ' '
+ }
+ )
+
+ expect(config.adapter_options[:encryption][:tls_options]).not_to have_key(:ca_file)
+ end
+ end
+
+ context 'when ssl_version is specified' do
+ it 'passes it through in tls_options' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'ssl_version' => 'TLSv1_2'
+ }
+ )
+
+ expect(config.adapter_options[:encryption][:tls_options]).to include({ ssl_version: 'TLSv1_2' })
+ end
+ end
+
+ context 'when ssl_version is a blank string' do
+ it 'does not add the ssl_version key to tls_options' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'ssl_version' => ' '
+ }
+ )
+
+ expect(config.adapter_options[:encryption][:tls_options]).not_to have_key(:ssl_version)
+ end
end
end
@@ -64,11 +180,11 @@ describe Gitlab::LDAP::Config, lib: true do
it 'constructs basic options' do
stub_ldap_config(
options: {
- 'host' => 'ldap.example.com',
- 'port' => 386,
- 'base' => 'ou=users,dc=example,dc=com',
- 'method' => 'plain',
- 'uid' => 'uid'
+ 'host' => 'ldap.example.com',
+ 'port' => 386,
+ 'base' => 'ou=users,dc=example,dc=com',
+ 'encryption' => 'plain',
+ 'uid' => 'uid'
}
)
@@ -76,7 +192,7 @@ describe Gitlab::LDAP::Config, lib: true do
host: 'ldap.example.com',
port: 386,
base: 'ou=users,dc=example,dc=com',
- method: 'plain',
+ encryption: 'plain',
filter: '(uid=%{username})'
)
expect(config.omniauth_options.keys).not_to include(:bind_dn, :password)
@@ -98,6 +214,100 @@ describe Gitlab::LDAP::Config, lib: true do
password: 'super_secret'
)
end
+
+ context 'when verify_certificates is enabled' do
+ it 'specifies disable_verify_certificates as false' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true
+ }
+ )
+
+ expect(config.omniauth_options).to include({ disable_verify_certificates: false })
+ end
+ end
+
+ context 'when verify_certificates is disabled' do
+ it 'specifies disable_verify_certificates as true' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => false
+ }
+ )
+
+ expect(config.omniauth_options).to include({ disable_verify_certificates: true })
+ end
+ end
+
+ context 'when ca_file is present' do
+ it 'passes it through' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'ca_file' => '/etc/ca.pem'
+ }
+ )
+
+ expect(config.omniauth_options).to include({ ca_file: '/etc/ca.pem' })
+ end
+ end
+
+ context 'when ca_file is blank' do
+ it 'does not include the ca_file option' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'ca_file' => ' '
+ }
+ )
+
+ expect(config.omniauth_options).not_to have_key(:ca_file)
+ end
+ end
+
+ context 'when ssl_version is present' do
+ it 'passes it through' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'ssl_version' => 'TLSv1_2'
+ }
+ )
+
+ expect(config.omniauth_options).to include({ ssl_version: 'TLSv1_2' })
+ end
+ end
+
+ context 'when ssl_version is blank' do
+ it 'does not include the ssl_version option' do
+ stub_ldap_config(
+ options: {
+ 'host' => 'ldap.example.com',
+ 'port' => 686,
+ 'encryption' => 'simple_tls',
+ 'verify_certificates' => true,
+ 'ssl_version' => ' '
+ }
+ )
+
+ expect(config.omniauth_options).not_to have_key(:ssl_version)
+ end
+ end
end
describe '#has_auth?' do
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index b796d8bf076..175ceec44d7 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::LDAP::User, lib: true do
- let(:ldap_user) { Gitlab::LDAP::User.new(auth_hash) }
+describe Gitlab::LDAP::User do
+ let(:ldap_user) { described_class.new(auth_hash) }
let(:gl_user) { ldap_user.gl_user }
let(:info) do
{
@@ -13,7 +13,7 @@ describe Gitlab::LDAP::User, lib: true do
let(:auth_hash) do
OmniAuth::AuthHash.new(uid: 'my-uid', provider: 'ldapmain', info: info)
end
- let(:ldap_user_upper_case) { Gitlab::LDAP::User.new(auth_hash_upper_case) }
+ let(:ldap_user_upper_case) { described_class.new(auth_hash_upper_case) }
let(:info_upper_case) do
{
name: 'John',
diff --git a/spec/lib/gitlab/lfs_token_spec.rb b/spec/lib/gitlab/lfs_token_spec.rb
index e9c1163e22a..3a20dad16d0 100644
--- a/spec/lib/gitlab/lfs_token_spec.rb
+++ b/spec/lib/gitlab/lfs_token_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LfsToken, lib: true do
+describe Gitlab::LfsToken do
describe '#token' do
shared_examples 'an LFS token generator' do
it 'returns a randomly generated token' do
diff --git a/spec/lib/gitlab/markup_helper_spec.rb b/spec/lib/gitlab/markup_helper_spec.rb
index 93b91b849f2..09e518ff989 100644
--- a/spec/lib/gitlab/markup_helper_spec.rb
+++ b/spec/lib/gitlab/markup_helper_spec.rb
@@ -1,40 +1,40 @@
require 'spec_helper'
-describe Gitlab::MarkupHelper, lib: true do
+describe Gitlab::MarkupHelper do
describe '#markup?' do
%w(textile rdoc org creole wiki
mediawiki rst adoc ad asciidoc mdown md markdown).each do |type|
it "returns true for #{type} files" do
- expect(Gitlab::MarkupHelper.markup?("README.#{type}")).to be_truthy
+ expect(described_class.markup?("README.#{type}")).to be_truthy
end
end
it 'returns false when given a non-markup filename' do
- expect(Gitlab::MarkupHelper.markup?('README.rb')).not_to be_truthy
+ expect(described_class.markup?('README.rb')).not_to be_truthy
end
end
describe '#gitlab_markdown?' do
%w(mdown mkd mkdn md markdown).each do |type|
it "returns true for #{type} files" do
- expect(Gitlab::MarkupHelper.gitlab_markdown?("README.#{type}")).to be_truthy
+ expect(described_class.gitlab_markdown?("README.#{type}")).to be_truthy
end
end
it 'returns false when given a non-markdown filename' do
- expect(Gitlab::MarkupHelper.gitlab_markdown?('README.rb')).not_to be_truthy
+ expect(described_class.gitlab_markdown?('README.rb')).not_to be_truthy
end
end
describe '#asciidoc?' do
%w(adoc ad asciidoc ADOC).each do |type|
it "returns true for #{type} files" do
- expect(Gitlab::MarkupHelper.asciidoc?("README.#{type}")).to be_truthy
+ expect(described_class.asciidoc?("README.#{type}")).to be_truthy
end
end
it 'returns false when given a non-asciidoc filename' do
- expect(Gitlab::MarkupHelper.asciidoc?('README.rb')).not_to be_truthy
+ expect(described_class.asciidoc?('README.rb')).not_to be_truthy
end
end
end
diff --git a/spec/lib/gitlab/metrics/sampler_spec.rb b/spec/lib/gitlab/metrics/influx_sampler_spec.rb
index d07ce6f81af..0bc68d64276 100644
--- a/spec/lib/gitlab/metrics/sampler_spec.rb
+++ b/spec/lib/gitlab/metrics/influx_sampler_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Metrics::Sampler do
+describe Gitlab::Metrics::InfluxSampler do
let(:sampler) { described_class.new(5) }
after do
@@ -8,10 +8,10 @@ describe Gitlab::Metrics::Sampler do
end
describe '#start' do
- it 'gathers a sample at a given interval' do
- expect(sampler).to receive(:sleep).with(a_kind_of(Numeric))
- expect(sampler).to receive(:sample)
- expect(sampler).to receive(:loop).and_yield
+ it 'runs once and gathers a sample at a given interval' do
+ expect(sampler).to receive(:sleep).with(a_kind_of(Numeric)).twice
+ expect(sampler).to receive(:sample).once
+ expect(sampler).to receive(:running).and_return(false, true, false)
sampler.start.join
end
diff --git a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
new file mode 100644
index 00000000000..461b1e4182a
--- /dev/null
+++ b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+
+describe Gitlab::Metrics::RequestsRackMiddleware do
+ let(:app) { double('app') }
+ subject { described_class.new(app) }
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ describe '#call' do
+ let(:status) { 100 }
+ let(:env) { { 'REQUEST_METHOD' => 'GET' } }
+ let(:stack_result) { [status, {}, 'body'] }
+
+ before do
+ allow(app).to receive(:call).and_return(stack_result)
+ end
+
+ context '@app.call succeeds with 200' do
+ before do
+ allow(app).to receive(:call).and_return([200, nil, nil])
+ end
+
+ it 'increments requests count' do
+ expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get')
+
+ subject.call(env)
+ end
+
+ it 'measures execution time' do
+ execution_time = 10
+ allow(app).to receive(:call) do |*args|
+ Timecop.freeze(execution_time.seconds)
+ [200, nil, nil]
+ end
+
+ expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ status: 200, method: 'get' }, execution_time)
+
+ subject.call(env)
+ end
+ end
+
+ context '@app.call throws exception' do
+ let(:http_request_duration_seconds) { double('http_request_duration_seconds') }
+
+ before do
+ allow(app).to receive(:call).and_raise(StandardError)
+ allow(described_class).to receive(:http_request_duration_seconds).and_return(http_request_duration_seconds)
+ end
+
+ it 'increments exceptions count' do
+ expect(described_class).to receive_message_chain(:rack_uncaught_errors_count, :increment)
+
+ expect { subject.call(env) }.to raise_error(StandardError)
+ end
+
+ it 'increments requests count' do
+ expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get')
+
+ expect { subject.call(env) }.to raise_error(StandardError)
+ end
+
+ it "does't measure request execution time" do
+ expect(described_class.http_request_duration_seconds).not_to receive(:increment)
+
+ expect { subject.call(env) }.to raise_error(StandardError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/metrics/unicorn_sampler_spec.rb b/spec/lib/gitlab/metrics/unicorn_sampler_spec.rb
new file mode 100644
index 00000000000..dc0d1f2e940
--- /dev/null
+++ b/spec/lib/gitlab/metrics/unicorn_sampler_spec.rb
@@ -0,0 +1,108 @@
+require 'spec_helper'
+
+describe Gitlab::Metrics::UnicornSampler do
+ subject { described_class.new(1.second) }
+
+ describe '#sample' do
+ let(:unicorn) { double('unicorn') }
+ let(:raindrops) { double('raindrops') }
+ let(:stats) { double('stats') }
+
+ before do
+ stub_const('Unicorn', unicorn)
+ stub_const('Raindrops::Linux', raindrops)
+ allow(raindrops).to receive(:unix_listener_stats).and_return({})
+ allow(raindrops).to receive(:tcp_listener_stats).and_return({})
+ end
+
+ context 'unicorn listens on unix sockets' do
+ let(:socket_address) { '/some/sock' }
+ let(:sockets) { [socket_address] }
+
+ before do
+ allow(unicorn).to receive(:listener_names).and_return(sockets)
+ end
+
+ it 'samples socket data' do
+ expect(raindrops).to receive(:unix_listener_stats).with(sockets)
+
+ subject.sample
+ end
+
+ context 'stats collected' do
+ before do
+ allow(stats).to receive(:active).and_return('active')
+ allow(stats).to receive(:queued).and_return('queued')
+ allow(raindrops).to receive(:unix_listener_stats).and_return({ socket_address => stats })
+ end
+
+ it 'updates metrics type unix and with addr' do
+ labels = { type: 'unix', address: socket_address }
+
+ expect(subject).to receive_message_chain(:unicorn_active_connections, :set).with(labels, 'active')
+ expect(subject).to receive_message_chain(:unicorn_queued_connections, :set).with(labels, 'queued')
+
+ subject.sample
+ end
+ end
+ end
+
+ context 'unicorn listens on tcp sockets' do
+ let(:tcp_socket_address) { '0.0.0.0:8080' }
+ let(:tcp_sockets) { [tcp_socket_address] }
+
+ before do
+ allow(unicorn).to receive(:listener_names).and_return(tcp_sockets)
+ end
+
+ it 'samples socket data' do
+ expect(raindrops).to receive(:tcp_listener_stats).with(tcp_sockets)
+
+ subject.sample
+ end
+
+ context 'stats collected' do
+ before do
+ allow(stats).to receive(:active).and_return('active')
+ allow(stats).to receive(:queued).and_return('queued')
+ allow(raindrops).to receive(:tcp_listener_stats).and_return({ tcp_socket_address => stats })
+ end
+
+ it 'updates metrics type unix and with addr' do
+ labels = { type: 'tcp', address: tcp_socket_address }
+
+ expect(subject).to receive_message_chain(:unicorn_active_connections, :set).with(labels, 'active')
+ expect(subject).to receive_message_chain(:unicorn_queued_connections, :set).with(labels, 'queued')
+
+ subject.sample
+ end
+ end
+ end
+ end
+
+ describe '#start' do
+ context 'when enabled' do
+ before do
+ allow(subject).to receive(:enabled?).and_return(true)
+ end
+
+ it 'creates new thread' do
+ expect(Thread).to receive(:new)
+
+ subject.start
+ end
+ end
+
+ context 'when disabled' do
+ before do
+ allow(subject).to receive(:enabled?).and_return(false)
+ end
+
+ it "doesn't create new thread" do
+ expect(Thread).not_to receive(:new)
+
+ subject.start
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb
index c2ab015d5cb..6af1564da19 100644
--- a/spec/lib/gitlab/middleware/go_spec.rb
+++ b/spec/lib/gitlab/middleware/go_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Middleware::Go, lib: true do
+describe Gitlab::Middleware::Go do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
index 19ab17419fc..d5f4da3ce36 100644
--- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Gitlab::OAuth::AuthHash, lib: true do
+describe Gitlab::OAuth::AuthHash do
let(:auth_hash) do
- Gitlab::OAuth::AuthHash.new(
+ described_class.new(
OmniAuth::AuthHash.new(
provider: provider_ascii,
uid: uid_ascii,
diff --git a/spec/lib/gitlab/o_auth/provider_spec.rb b/spec/lib/gitlab/o_auth/provider_spec.rb
index 1e2a1f8c039..30faf107e3f 100644
--- a/spec/lib/gitlab/o_auth/provider_spec.rb
+++ b/spec/lib/gitlab/o_auth/provider_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::OAuth::Provider, lib: true do
+describe Gitlab::OAuth::Provider do
describe '#config_for' do
context 'for an LDAP provider' do
context 'when the provider exists' do
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index ea29cb9caf1..47aa19d5fd9 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::OAuth::User, lib: true do
- let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) }
+describe Gitlab::OAuth::User do
+ let(:oauth_user) { described_class.new(auth_hash) }
let(:gl_user) { oauth_user.gl_user }
let(:uid) { 'my-uid' }
let(:provider) { 'my-provider' }
diff --git a/spec/lib/gitlab/optimistic_locking_spec.rb b/spec/lib/gitlab/optimistic_locking_spec.rb
index acce2be93f2..81f81d4f963 100644
--- a/spec/lib/gitlab/optimistic_locking_spec.rb
+++ b/spec/lib/gitlab/optimistic_locking_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::OptimisticLocking, lib: true do
+describe Gitlab::OptimisticLocking do
let!(:pipeline) { create(:ci_pipeline) }
let!(:pipeline2) { Ci::Pipeline.find(pipeline.id) }
diff --git a/spec/lib/gitlab/other_markup_spec.rb b/spec/lib/gitlab/other_markup_spec.rb
index c0f5fa9dc1f..e26f39e193e 100644
--- a/spec/lib/gitlab/other_markup_spec.rb
+++ b/spec/lib/gitlab/other_markup_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::OtherMarkup, lib: true do
+describe Gitlab::OtherMarkup do
let(:context) { {} }
context "XSS Checks" do
diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb
index 1eea710c80b..2f989397f7e 100644
--- a/spec/lib/gitlab/path_regex_spec.rb
+++ b/spec/lib/gitlab/path_regex_spec.rb
@@ -1,7 +1,7 @@
# coding: utf-8
require 'spec_helper'
-describe Gitlab::PathRegex, lib: true do
+describe Gitlab::PathRegex do
# Pass in a full path to remove the format segment:
# `/ci/lint(.:format)` -> `/ci/lint`
def without_format(path)
@@ -36,9 +36,12 @@ describe Gitlab::PathRegex, lib: true do
described_class::PROJECT_WILDCARD_ROUTES.include?(path.split('/').first)
end
- def failure_message(missing_words, constant_name, migration_helper)
+ def failure_message(constant_name, migration_helper, missing_words: [], additional_words: [])
missing_words = Array(missing_words)
- <<-MSG
+ additional_words = Array(additional_words)
+ message = ""
+ if missing_words.any?
+ message += <<-MISSING
Found new routes that could cause conflicts with existing namespaced routes
for groups or projects.
@@ -51,7 +54,18 @@ describe Gitlab::PathRegex, lib: true do
Make sure to make a note of the renamed records in the release blog post.
- MSG
+ MISSING
+ end
+
+ if additional_words.any?
+ message += <<-ADDITIONAL
+ Why are <#{additional_words.join(', ')}> in `#{constant_name}`?
+ If they are really required, update these specs to reflect that.
+
+ ADDITIONAL
+ end
+
+ message
end
let(:all_routes) do
@@ -68,9 +82,23 @@ describe Gitlab::PathRegex, lib: true do
let(:routes_not_starting_in_wildcard) { routes_without_format.select { |p| p !~ %r{^/[:*]} } }
let(:top_level_words) do
- routes_not_starting_in_wildcard.map do |route|
+ words = routes_not_starting_in_wildcard.map do |route|
route.split('/')[1]
end.compact.uniq
+
+ words + ee_top_level_words + files_in_public + Array(API::API.prefix.to_s)
+ end
+
+ let(:ee_top_level_words) do
+ ['unsubscribes']
+ end
+
+ let(:files_in_public) do
+ git = Gitlab.config.git.bin_path
+ `cd #{Rails.root} && #{git} ls-files public`
+ .split("\n")
+ .map { |entry| entry.gsub('public/', '') }
+ .uniq
end
# All routes that start with a namespaced path, that have 1 or more
@@ -115,18 +143,29 @@ describe Gitlab::PathRegex, lib: true do
let(:paths_after_group_id) do
group_routes.map do |route|
route.gsub(STARTING_WITH_GROUP, '').split('/').first
- end.uniq
+ end.uniq + ee_paths_after_group_id
+ end
+
+ let(:ee_paths_after_group_id) do
+ %w(analytics
+ ldap
+ ldap_group_links
+ notification_setting
+ audit_events
+ pipeline_quota hooks)
end
describe 'TOP_LEVEL_ROUTES' do
it 'includes all the top level namespaces' do
failure_block = lambda do
missing_words = top_level_words - described_class::TOP_LEVEL_ROUTES
- failure_message(missing_words, 'TOP_LEVEL_ROUTES', 'rename_root_paths')
+ additional_words = described_class::TOP_LEVEL_ROUTES - top_level_words
+ failure_message('TOP_LEVEL_ROUTES', 'rename_root_paths',
+ missing_words: missing_words, additional_words: additional_words)
end
expect(described_class::TOP_LEVEL_ROUTES)
- .to include(*top_level_words), failure_block
+ .to contain_exactly(*top_level_words), failure_block
end
end
@@ -134,11 +173,13 @@ describe Gitlab::PathRegex, lib: true do
it "don't contain a second wildcard" do
failure_block = lambda do
missing_words = paths_after_group_id - described_class::GROUP_ROUTES
- failure_message(missing_words, 'GROUP_ROUTES', 'rename_child_paths')
+ additional_words = described_class::GROUP_ROUTES - paths_after_group_id
+ failure_message('GROUP_ROUTES', 'rename_child_paths',
+ missing_words: missing_words, additional_words: additional_words)
end
expect(described_class::GROUP_ROUTES)
- .to include(*paths_after_group_id), failure_block
+ .to contain_exactly(*paths_after_group_id), failure_block
end
end
@@ -147,7 +188,7 @@ describe Gitlab::PathRegex, lib: true do
aggregate_failures do
all_wildcard_paths.each do |path|
expect(wildcards_include?(path))
- .to be(true), failure_message(path, 'PROJECT_WILDCARD_ROUTES', 'rename_wildcard_paths')
+ .to be(true), failure_message('PROJECT_WILDCARD_ROUTES', 'rename_wildcard_paths', missing_words: path)
end
end
end
diff --git a/spec/lib/gitlab/performance_bar_spec.rb b/spec/lib/gitlab/performance_bar_spec.rb
new file mode 100644
index 00000000000..b8a2267f1a4
--- /dev/null
+++ b/spec/lib/gitlab/performance_bar_spec.rb
@@ -0,0 +1,92 @@
+require 'spec_helper'
+
+describe Gitlab::PerformanceBar do
+ shared_examples 'allowed user IDs are cached' do
+ before do
+ # Warm the Redis cache
+ described_class.enabled?(user)
+ end
+
+ it 'caches the allowed user IDs in cache', :use_clean_rails_memory_store_caching do
+ expect do
+ expect(described_class.enabled?(user)).to be_truthy
+ end.not_to exceed_query_limit(0)
+ end
+ end
+
+ describe '.enabled?' do
+ let(:user) { create(:user) }
+
+ before do
+ stub_application_setting(performance_bar_allowed_group_id: -1)
+ end
+
+ it 'returns false when given user is nil' do
+ expect(described_class.enabled?(nil)).to be_falsy
+ end
+
+ it 'returns false when allowed_group_id is nil' do
+ expect(described_class).to receive(:allowed_group_id).and_return(nil)
+
+ expect(described_class.enabled?(user)).to be_falsy
+ end
+
+ context 'when allowed group ID does not exist' do
+ it 'returns false' do
+ expect(described_class.enabled?(user)).to be_falsy
+ end
+ end
+
+ context 'when allowed group exists' do
+ let!(:my_group) { create(:group, path: 'my-group') }
+
+ before do
+ stub_application_setting(performance_bar_allowed_group_id: my_group.id)
+ end
+
+ context 'when user is not a member of the allowed group' do
+ it 'returns false' do
+ expect(described_class.enabled?(user)).to be_falsy
+ end
+
+ it_behaves_like 'allowed user IDs are cached'
+ end
+
+ context 'when user is a member of the allowed group' do
+ before do
+ my_group.add_developer(user)
+ end
+
+ it 'returns true' do
+ expect(described_class.enabled?(user)).to be_truthy
+ end
+
+ it_behaves_like 'allowed user IDs are cached'
+ end
+ end
+
+ context 'when allowed group is nested', :nested_groups do
+ let!(:nested_my_group) { create(:group, parent: create(:group, path: 'my-org'), path: 'my-group') }
+
+ before do
+ create(:group, path: 'my-group')
+ nested_my_group.add_developer(user)
+ stub_application_setting(performance_bar_allowed_group_id: nested_my_group.id)
+ end
+
+ it 'returns the nested group' do
+ expect(described_class.enabled?(user)).to be_truthy
+ end
+ end
+
+ context 'when a nested group has the same path', :nested_groups do
+ before do
+ create(:group, :nested, path: 'my-group').add_developer(user)
+ end
+
+ it 'returns false' do
+ expect(described_class.enabled?(user)).to be_falsy
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/polling_interval_spec.rb b/spec/lib/gitlab/polling_interval_spec.rb
index 5ea8ecb1c30..eb8e618156b 100644
--- a/spec/lib/gitlab/polling_interval_spec.rb
+++ b/spec/lib/gitlab/polling_interval_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::PollingInterval, lib: true do
+describe Gitlab::PollingInterval do
let(:polling_interval) { described_class }
describe '.set_header' do
diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb
index 4ae216d55b0..4567f220c11 100644
--- a/spec/lib/gitlab/popen_spec.rb
+++ b/spec/lib/gitlab/popen_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::Popen', lib: true, no_db: true do
+describe 'Gitlab::Popen' do
let(:path) { Rails.root.join('tmp').to_s }
before do
@@ -32,6 +32,17 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
end
end
+ context 'with custom options' do
+ let(:vars) { { 'foobar' => 123, 'PWD' => path } }
+ let(:options) { { chdir: path } }
+
+ it 'calls popen3 with the provided environment variables' do
+ expect(Open3).to receive(:popen3).with(vars, 'ls', options)
+
+ @output, @status = @klass.new.popen(%w(ls), path, { 'foobar' => 123 })
+ end
+ end
+
context 'without a directory argument' do
before do
@output, @status = @klass.new.popen(%w(ls))
@@ -45,7 +56,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do
before do
@output, @status = @klass.new.popen(%w[cat]) { |stdin| stdin.write 'hello' }
end
-
+
it { expect(@status).to be_zero }
it { expect(@output).to eq('hello') }
end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 3d22784909d..d17b436b910 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ProjectSearchResults, lib: true do
+describe Gitlab::ProjectSearchResults do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:query) { 'hello world' }
diff --git a/spec/lib/gitlab/project_transfer_spec.rb b/spec/lib/gitlab/project_transfer_spec.rb
index e2d6b1b9ab7..10c5fb148cd 100644
--- a/spec/lib/gitlab/project_transfer_spec.rb
+++ b/spec/lib/gitlab/project_transfer_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Gitlab::ProjectTransfer, lib: true do
+describe Gitlab::ProjectTransfer do
before do
@root_dir = File.join(Rails.root, "public", "uploads")
- @project_transfer = Gitlab::ProjectTransfer.new
+ @project_transfer = described_class.new
allow(@project_transfer).to receive(:root_dir).and_return(@root_dir)
@project_path_was = "test_project_was"
diff --git a/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb b/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb
new file mode 100644
index 00000000000..d7df4e35c31
--- /dev/null
+++ b/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb
@@ -0,0 +1,246 @@
+require 'spec_helper'
+
+describe Gitlab::Prometheus::AdditionalMetricsParser do
+ include Prometheus::MetricBuilders
+
+ let(:parser_error_class) { Gitlab::Prometheus::ParsingError }
+
+ describe '#load_groups_from_yaml' do
+ subject { described_class.load_groups_from_yaml }
+
+ describe 'parsing sample yaml' do
+ let(:sample_yaml) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: "title"
+ required_metrics: [ metric_a, metric_b ]
+ weight: 1
+ queries: [{ query_range: 'query_range_a', label: label, unit: unit }]
+ - title: "title"
+ required_metrics: [metric_a]
+ weight: 1
+ queries: [{ query_range: 'query_range_empty' }]
+ - group: group_b
+ priority: 1
+ metrics:
+ - title: title
+ required_metrics: ['metric_a']
+ weight: 1
+ queries: [{query_range: query_range_a}]
+ EOF
+ end
+
+ before do
+ allow(described_class).to receive(:load_yaml_file) { YAML.load(sample_yaml) }
+ end
+
+ it 'parses to two metric groups with 2 and 1 metric respectively' do
+ expect(subject.count).to eq(2)
+ expect(subject[0].metrics.count).to eq(2)
+ expect(subject[1].metrics.count).to eq(1)
+ end
+
+ it 'provide group data' do
+ expect(subject[0]).to have_attributes(name: 'group_a', priority: 1)
+ expect(subject[1]).to have_attributes(name: 'group_b', priority: 1)
+ end
+
+ it 'provides metrics data' do
+ metrics = subject.flat_map(&:metrics)
+
+ expect(metrics.count).to eq(3)
+ expect(metrics[0]).to have_attributes(title: 'title', required_metrics: %w(metric_a metric_b), weight: 1)
+ expect(metrics[1]).to have_attributes(title: 'title', required_metrics: %w(metric_a), weight: 1)
+ expect(metrics[2]).to have_attributes(title: 'title', required_metrics: %w{metric_a}, weight: 1)
+ end
+
+ it 'provides query data' do
+ queries = subject.flat_map(&:metrics).flat_map(&:queries)
+
+ expect(queries.count).to eq(3)
+ expect(queries[0]).to eq(query_range: 'query_range_a', label: 'label', unit: 'unit')
+ expect(queries[1]).to eq(query_range: 'query_range_empty')
+ expect(queries[2]).to eq(query_range: 'query_range_a')
+ end
+ end
+
+ shared_examples 'required field' do |field_name|
+ context "when #{field_name} is nil" do
+ before do
+ allow(described_class).to receive(:load_yaml_file) { YAML.load(field_missing) }
+ end
+
+ it 'throws parsing error' do
+ expect { subject }.to raise_error(parser_error_class, /#{field_name} can't be blank/i)
+ end
+ end
+
+ context "when #{field_name} are not specified" do
+ before do
+ allow(described_class).to receive(:load_yaml_file) { YAML.load(field_nil) }
+ end
+
+ it 'throws parsing error' do
+ expect { subject }.to raise_error(parser_error_class, /#{field_name} can't be blank/i)
+ end
+ end
+ end
+
+ describe 'group required fields' do
+ it_behaves_like 'required field', 'metrics' do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ EOF
+ end
+ end
+
+ it_behaves_like 'required field', 'name' do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group:
+ priority: 1
+ metrics: []
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - priority: 1
+ metrics: []
+ EOF
+ end
+ end
+
+ it_behaves_like 'required field', 'priority' do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority:
+ metrics: []
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ metrics: []
+ EOF
+ end
+ end
+ end
+
+ describe 'metrics fields parsing' do
+ it_behaves_like 'required field', 'title' do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title:
+ required_metrics: []
+ weight: 1
+ queries: []
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - required_metrics: []
+ weight: 1
+ queries: []
+ EOF
+ end
+ end
+
+ it_behaves_like 'required field', 'required metrics' do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: title
+ required_metrics:
+ weight: 1
+ queries: []
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: title
+ weight: 1
+ queries: []
+ EOF
+ end
+ end
+
+ it_behaves_like 'required field', 'weight' do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: title
+ required_metrics: []
+ weight:
+ queries: []
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: title
+ required_metrics: []
+ queries: []
+ EOF
+ end
+ end
+
+ it_behaves_like 'required field', :queries do
+ let(:field_nil) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: title
+ required_metrics: []
+ weight: 1
+ queries:
+ EOF
+ end
+
+ let(:field_missing) do
+ <<-EOF.strip_heredoc
+ - group: group_a
+ priority: 1
+ metrics:
+ - title: title
+ required_metrics: []
+ weight: 1
+ EOF
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
new file mode 100644
index 00000000000..e42e034f4fb
--- /dev/null
+++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do
+ include Prometheus::MetricBuilders
+
+ let(:client) { double('prometheus_client') }
+ let(:environment) { create(:environment, slug: 'environment-slug') }
+ let(:deployment) { create(:deployment, environment: environment) }
+
+ subject(:query_result) { described_class.new(client).query(deployment.id) }
+
+ around do |example|
+ Timecop.freeze(Time.local(2008, 9, 1, 12, 0, 0)) { example.run }
+ end
+
+ include_examples 'additional metrics query' do
+ it 'queries using specific time' do
+ expect(client).to receive(:query_range).with(anything,
+ start: (deployment.created_at - 30.minutes).to_f,
+ stop: (deployment.created_at + 30.minutes).to_f)
+
+ expect(query_result).not_to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb
new file mode 100644
index 00000000000..e9fd66d45fe
--- /dev/null
+++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery do
+ include Prometheus::MetricBuilders
+
+ let(:client) { double('prometheus_client') }
+ let(:environment) { create(:environment, slug: 'environment-slug') }
+
+ subject(:query_result) { described_class.new(client).query(environment.id) }
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ include_examples 'additional metrics query' do
+ it 'queries using specific time' do
+ expect(client).to receive(:query_range).with(anything, start: 8.hours.ago.to_f, stop: Time.now.to_f)
+ expect(query_result).not_to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
index d957dd932c4..ffe3ad85baa 100644
--- a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Prometheus::Queries::DeploymentQuery, lib: true do
+describe Gitlab::Prometheus::Queries::DeploymentQuery do
let(:environment) { create(:environment, slug: 'environment-slug') }
let(:deployment) { create(:deployment, environment: environment) }
diff --git a/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb b/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb
new file mode 100644
index 00000000000..2b488101496
--- /dev/null
+++ b/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb
@@ -0,0 +1,134 @@
+require 'spec_helper'
+
+describe Gitlab::Prometheus::Queries::MatchedMetricsQuery do
+ include Prometheus::MetricBuilders
+
+ let(:metric_group_class) { Gitlab::Prometheus::MetricGroup }
+ let(:metric_class) { Gitlab::Prometheus::Metric }
+
+ def series_info_with_environment(*more_metrics)
+ %w{metric_a metric_b}.concat(more_metrics).map { |metric_name| { '__name__' => metric_name, 'environment' => '' } }
+ end
+
+ let(:metric_names) { %w{metric_a metric_b} }
+ let(:series_info_without_environment) do
+ [{ '__name__' => 'metric_a' },
+ { '__name__' => 'metric_b' }]
+ end
+ let(:partialy_empty_series_info) { [{ '__name__' => 'metric_a', 'environment' => '' }] }
+ let(:empty_series_info) { [] }
+
+ let(:client) { double('prometheus_client') }
+
+ subject { described_class.new(client) }
+
+ context 'with one group where two metrics is found' do
+ before do
+ allow(metric_group_class).to receive(:all).and_return([simple_metric_group])
+ allow(client).to receive(:label_values).and_return(metric_names)
+ end
+
+ context 'both metrics in the group pass requirements' do
+ before do
+ allow(client).to receive(:series).and_return(series_info_with_environment)
+ end
+
+ it 'responds with both metrics as actve' do
+ expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 2, metrics_missing_requirements: 0 }])
+ end
+ end
+
+ context 'none of the metrics pass requirements' do
+ before do
+ allow(client).to receive(:series).and_return(series_info_without_environment)
+ end
+
+ it 'responds with both metrics missing requirements' do
+ expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 0, metrics_missing_requirements: 2 }])
+ end
+ end
+
+ context 'no series information found about the metrics' do
+ before do
+ allow(client).to receive(:series).and_return(empty_series_info)
+ end
+
+ it 'responds with both metrics missing requirements' do
+ expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 0, metrics_missing_requirements: 2 }])
+ end
+ end
+
+ context 'one of the series info was not found' do
+ before do
+ allow(client).to receive(:series).and_return(partialy_empty_series_info)
+ end
+ it 'responds with one active and one missing metric' do
+ expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 1, metrics_missing_requirements: 1 }])
+ end
+ end
+ end
+
+ context 'with one group where only one metric is found' do
+ before do
+ allow(metric_group_class).to receive(:all).and_return([simple_metric_group])
+ allow(client).to receive(:label_values).and_return('metric_a')
+ end
+
+ context 'both metrics in the group pass requirements' do
+ before do
+ allow(client).to receive(:series).and_return(series_info_with_environment)
+ end
+
+ it 'responds with one metrics as active and no missing requiremens' do
+ expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 1, metrics_missing_requirements: 0 }])
+ end
+ end
+
+ context 'no metrics in group pass requirements' do
+ before do
+ allow(client).to receive(:series).and_return(series_info_without_environment)
+ end
+
+ it 'responds with one metrics as active and no missing requiremens' do
+ expect(subject.query).to eq([{ group: 'name', priority: 1, active_metrics: 0, metrics_missing_requirements: 1 }])
+ end
+ end
+ end
+
+ context 'with two groups where metrics are found in each group' do
+ let(:second_metric_group) { simple_metric_group(name: 'nameb', metrics: simple_metrics(added_metric_name: 'metric_c')) }
+
+ before do
+ allow(metric_group_class).to receive(:all).and_return([simple_metric_group, second_metric_group])
+ allow(client).to receive(:label_values).and_return('metric_c')
+ end
+
+ context 'all metrics in both groups pass requirements' do
+ before do
+ allow(client).to receive(:series).and_return(series_info_with_environment('metric_c'))
+ end
+
+ it 'responds with one metrics as active and no missing requiremens' do
+ expect(subject.query).to eq([
+ { group: 'name', priority: 1, active_metrics: 1, metrics_missing_requirements: 0 },
+ { group: 'nameb', priority: 1, active_metrics: 2, metrics_missing_requirements: 0 }
+ ]
+ )
+ end
+ end
+
+ context 'no metrics in groups pass requirements' do
+ before do
+ allow(client).to receive(:series).and_return(series_info_without_environment)
+ end
+
+ it 'responds with one metrics as active and no missing requiremens' do
+ expect(subject.query).to eq([
+ { group: 'name', priority: 1, active_metrics: 0, metrics_missing_requirements: 1 },
+ { group: 'nameb', priority: 1, active_metrics: 0, metrics_missing_requirements: 2 }
+ ]
+ )
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/prometheus_client_spec.rb b/spec/lib/gitlab/prometheus_client_spec.rb
index 2d8bd2f6b97..de625324092 100644
--- a/spec/lib/gitlab/prometheus_client_spec.rb
+++ b/spec/lib/gitlab/prometheus_client_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::PrometheusClient, lib: true do
+describe Gitlab::PrometheusClient do
include PrometheusHelpers
subject { described_class.new(api_url: 'https://prometheus.example.com') }
@@ -119,6 +119,36 @@ describe Gitlab::PrometheusClient, lib: true do
end
end
+ describe '#series' do
+ let(:query_url) { prometheus_series_url('series_name', 'other_service') }
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'calls endpoint and returns list of series' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_series('series_name'))
+ expected = prometheus_series('series_name').deep_stringify_keys['data']
+
+ expect(subject.series('series_name', 'other_service')).to eq(expected)
+
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ describe '#label_values' do
+ let(:query_url) { prometheus_label_values_url('__name__') }
+
+ it 'calls endpoint and returns label values' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_label_values)
+ expected = prometheus_label_values.deep_stringify_keys['data']
+
+ expect(subject.label_values('__name__')).to eq(expected)
+
+ expect(req_stub).to have_been_requested
+ end
+ end
+
describe '#query_range' do
let(:prometheus_query) { prometheus_memory_query('env-slug') }
let(:query_url) { prometheus_query_range_url(prometheus_query) }
diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb
index a4bb3f911d7..ff59dc48bcb 100644
--- a/spec/lib/gitlab/quick_actions/dsl_spec.rb
+++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb
@@ -42,13 +42,18 @@ describe Gitlab::QuickActions::Dsl do
command :with_params_parsing do |parsed|
parsed
end
+
+ params '<Comment>'
+ substitution :something do |text|
+ "#{text} Some complicated thing you want in here"
+ end
end
end
describe '.command_definitions' do
it 'returns an array with commands definitions' do
no_args_def, explanation_with_aliases_def, dynamic_description_def,
- cc_def, cond_action_def, with_params_parsing_def =
+ cc_def, cond_action_def, with_params_parsing_def, substitution_def =
DummyClass.command_definitions
expect(no_args_def.name).to eq(:no_args)
@@ -104,6 +109,15 @@ describe Gitlab::QuickActions::Dsl do
expect(with_params_parsing_def.condition_block).to be_nil
expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc)
expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc)
+
+ expect(substitution_def.name).to eq(:something)
+ expect(substitution_def.aliases).to eq([])
+ expect(substitution_def.description).to eq('')
+ expect(substitution_def.explanation).to eq('')
+ expect(substitution_def.params).to eq(['<Comment>'])
+ expect(substitution_def.condition_block).to be_nil
+ expect(substitution_def.action_block.call('text')).to eq('text Some complicated thing you want in here')
+ expect(substitution_def.parse_params_block).to be_nil
end
end
end
diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb
index 9d32938e155..f7c288f2393 100644
--- a/spec/lib/gitlab/quick_actions/extractor_spec.rb
+++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb
@@ -9,6 +9,11 @@ describe Gitlab::QuickActions::Extractor do
command(:assign) { }
command(:labels) { }
command(:power) { }
+ command(:noop_command)
+ substitution(:substitution) { 'foo' }
+ substitution :shrug do |comment|
+ "#{comment} SHRUG"
+ end
end.command_definitions
end
@@ -177,6 +182,38 @@ describe Gitlab::QuickActions::Extractor do
expect(msg).to eq "hello\nworld"
end
+ it 'does not extract noop commands' do
+ msg = %(hello\nworld\n/reopen\n/noop_command)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen']]
+ expect(msg).to eq "hello\nworld\n/noop_command"
+ end
+
+ it 'extracts and performs substitution commands' do
+ msg = %(hello\nworld\n/reopen\n/substitution)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen'], ['substitution']]
+ expect(msg).to eq "hello\nworld\nfoo"
+ end
+
+ it 'extracts and performs substitution commands' do
+ msg = %(hello\nworld\n/reopen\n/shrug this is great?)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen'], ['shrug', 'this is great?']]
+ expect(msg).to eq "hello\nworld\nthis is great? SHRUG"
+ end
+
+ it 'extracts and performs substitution commands with comments' do
+ msg = %(hello\nworld\n/reopen\n/substitution wow this is a thing.)
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['reopen'], ['substitution', 'wow this is a thing.']]
+ expect(msg).to eq "hello\nworld\nfoo"
+ end
+
it 'extracts multiple commands' do
msg = %(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/reopen)
msg, commands = extractor.extract_commands(msg)
diff --git a/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb
new file mode 100644
index 00000000000..1bb8bc51c96
--- /dev/null
+++ b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe Gitlab::QuickActions::SubstitutionDefinition do
+ let(:content) do
+ <<EOF
+Hello! Let's do this!
+/sub_name I like this stuff
+EOF
+ end
+ subject do
+ described_class.new(:sub_name, action_block: proc { |text| "#{text} foo" })
+ end
+
+ describe '#perform_substitution!' do
+ it 'returns nil if content is nil' do
+ expect(subject.perform_substitution(self, nil)).to be_nil
+ end
+
+ it 'performs the substitution by default' do
+ expect(subject.perform_substitution(self, content)).to eq <<EOF
+Hello! Let's do this!
+I like this stuff foo
+EOF
+ end
+ end
+
+ describe '#match' do
+ it 'checks the content for the command' do
+ expect(subject.match(content)).to be_truthy
+ end
+
+ it 'returns the match data' do
+ data = subject.match(content)
+ expect(data).to be_a(MatchData)
+ expect(data[1]).to eq('I like this stuff')
+ end
+
+ it 'is nil if content does not have the command' do
+ expect(subject.match('blah')).to be_falsey
+ end
+ end
+end
diff --git a/spec/lib/gitlab/redis/cache_spec.rb b/spec/lib/gitlab/redis/cache_spec.rb
new file mode 100644
index 00000000000..5a4f17cfcf6
--- /dev/null
+++ b/spec/lib/gitlab/redis/cache_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::Redis::Cache do
+ let(:config_file_name) { "config/redis.cache.yml" }
+ let(:environment_config_file_name) { "GITLAB_REDIS_CACHE_CONFIG_FILE" }
+ let(:config_old_format_socket) { "spec/fixtures/config/redis_cache_old_format_socket.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_cache_new_format_socket.yml" }
+ let(:old_socket_path) {"/path/to/old/redis.cache.sock" }
+ let(:new_socket_path) {"/path/to/redis.cache.sock" }
+ let(:config_old_format_host) { "spec/fixtures/config/redis_cache_old_format_host.yml" }
+ let(:config_new_format_host) { "spec/fixtures/config/redis_cache_new_format_host.yml" }
+ let(:redis_port) { 6380 }
+ let(:redis_database) { 10 }
+ let(:sentinel_port) { redis_port + 20000 }
+ let(:config_with_environment_variable_inside) { "spec/fixtures/config/redis_cache_config_with_env.yml"}
+ let(:config_env_variable_url) {"TEST_GITLAB_REDIS_CACHE_URL"}
+ let(:class_redis_url) { Gitlab::Redis::Cache::DEFAULT_REDIS_CACHE_URL }
+
+ include_examples "redis_shared_examples"
+end
diff --git a/spec/lib/gitlab/redis/queues_spec.rb b/spec/lib/gitlab/redis/queues_spec.rb
new file mode 100644
index 00000000000..01ca25635a9
--- /dev/null
+++ b/spec/lib/gitlab/redis/queues_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::Redis::Queues do
+ let(:config_file_name) { "config/redis.queues.yml" }
+ let(:environment_config_file_name) { "GITLAB_REDIS_QUEUES_CONFIG_FILE" }
+ let(:config_old_format_socket) { "spec/fixtures/config/redis_queues_old_format_socket.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_queues_new_format_socket.yml" }
+ let(:old_socket_path) {"/path/to/old/redis.queues.sock" }
+ let(:new_socket_path) {"/path/to/redis.queues.sock" }
+ let(:config_old_format_host) { "spec/fixtures/config/redis_queues_old_format_host.yml" }
+ let(:config_new_format_host) { "spec/fixtures/config/redis_queues_new_format_host.yml" }
+ let(:redis_port) { 6381 }
+ let(:redis_database) { 11 }
+ let(:sentinel_port) { redis_port + 20000 }
+ let(:config_with_environment_variable_inside) { "spec/fixtures/config/redis_queues_config_with_env.yml"}
+ let(:config_env_variable_url) {"TEST_GITLAB_REDIS_QUEUES_URL"}
+ let(:class_redis_url) { Gitlab::Redis::Queues::DEFAULT_REDIS_QUEUES_URL }
+
+ include_examples "redis_shared_examples"
+end
diff --git a/spec/lib/gitlab/redis/shared_state_spec.rb b/spec/lib/gitlab/redis/shared_state_spec.rb
new file mode 100644
index 00000000000..24b73745dc5
--- /dev/null
+++ b/spec/lib/gitlab/redis/shared_state_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::Redis::SharedState do
+ let(:config_file_name) { "config/redis.shared_state.yml" }
+ let(:environment_config_file_name) { "GITLAB_REDIS_SHARED_STATE_CONFIG_FILE" }
+ let(:config_old_format_socket) { "spec/fixtures/config/redis_shared_state_old_format_socket.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_shared_state_new_format_socket.yml" }
+ let(:old_socket_path) {"/path/to/old/redis.shared_state.sock" }
+ let(:new_socket_path) {"/path/to/redis.shared_state.sock" }
+ let(:config_old_format_host) { "spec/fixtures/config/redis_shared_state_old_format_host.yml" }
+ let(:config_new_format_host) { "spec/fixtures/config/redis_shared_state_new_format_host.yml" }
+ let(:redis_port) { 6382 }
+ let(:redis_database) { 12 }
+ let(:sentinel_port) { redis_port + 20000 }
+ let(:config_with_environment_variable_inside) { "spec/fixtures/config/redis_shared_state_config_with_env.yml"}
+ let(:config_env_variable_url) {"TEST_GITLAB_REDIS_SHARED_STATE_URL"}
+ let(:class_redis_url) { Gitlab::Redis::SharedState::DEFAULT_REDIS_SHARED_STATE_URL }
+
+ include_examples "redis_shared_examples"
+end
diff --git a/spec/lib/gitlab/redis/wrapper_spec.rb b/spec/lib/gitlab/redis/wrapper_spec.rb
new file mode 100644
index 00000000000..e1becd0a614
--- /dev/null
+++ b/spec/lib/gitlab/redis/wrapper_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::Redis::Wrapper do
+ let(:config_file_name) { "config/resque.yml" }
+ let(:environment_config_file_name) { "GITLAB_REDIS_CONFIG_FILE" }
+ let(:config_old_format_socket) { "spec/fixtures/config/redis_old_format_socket.yml" }
+ let(:config_new_format_socket) { "spec/fixtures/config/redis_new_format_socket.yml" }
+ let(:old_socket_path) {"/path/to/old/redis.sock" }
+ let(:new_socket_path) {"/path/to/redis.sock" }
+ let(:config_old_format_host) { "spec/fixtures/config/redis_old_format_host.yml" }
+ let(:config_new_format_host) { "spec/fixtures/config/redis_new_format_host.yml" }
+ let(:redis_port) { 6379 }
+ let(:redis_database) { 99 }
+ let(:sentinel_port) { redis_port + 20000 }
+ let(:config_with_environment_variable_inside) { "spec/fixtures/config/redis_config_with_env.yml"}
+ let(:config_env_variable_url) {"TEST_GITLAB_REDIS_URL"}
+ let(:class_redis_url) { Gitlab::Redis::Wrapper::DEFAULT_REDIS_URL }
+
+ include_examples "redis_shared_examples"
+end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 84cfd934fa0..1a0357534f2 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-describe Gitlab::ReferenceExtractor, lib: true do
+describe Gitlab::ReferenceExtractor do
let(:project) { create(:empty_project) }
before do
project.team << [project.creator, :developer]
end
- subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
+ subject { described_class.new(project, project.creator) }
it 'accesses valid user objects' do
@u_foo = create(:user, username: 'foo')
@@ -183,11 +183,34 @@ describe Gitlab::ReferenceExtractor, lib: true do
context 'with an external issue tracker' do
let(:project) { create(:jira_project) }
+ let(:issue) { create(:issue, project: project) }
+
+ context 'when GitLab issues are enabled' do
+ it 'returns both JIRA and internal issues' do
+ subject.analyze("JIRA-123 and FOOBAR-4567 and #{issue.to_reference}")
+ expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
+ ExternalIssue.new('FOOBAR-4567', project),
+ issue]
+ end
+
+ it 'returns only JIRA issues if the internal one does not exists' do
+ subject.analyze("JIRA-123 and FOOBAR-4567 and #999")
+ expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
+ ExternalIssue.new('FOOBAR-4567', project)]
+ end
+ end
- it 'returns JIRA issues for a JIRA-integrated project' do
- subject.analyze('JIRA-123 and FOOBAR-4567')
- expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
- ExternalIssue.new('FOOBAR-4567', project)]
+ context 'when GitLab issues are disabled' do
+ before do
+ project.issues_enabled = false
+ project.save!
+ end
+
+ it 'returns only JIRA issues' do
+ subject.analyze("JIRA-123 and FOOBAR-4567 and #{issue.to_reference}")
+ expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
+ ExternalIssue.new('FOOBAR-4567', project)]
+ end
end
end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 979f4fefcb6..68a57826647 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -1,7 +1,7 @@
# coding: utf-8
require 'spec_helper'
-describe Gitlab::Regex, lib: true do
+describe Gitlab::Regex do
describe '.project_name_regex' do
subject { described_class.project_name_regex }
@@ -14,12 +14,6 @@ describe Gitlab::Regex, lib: true do
it { is_expected.not_to match('?gitlab') }
end
- describe '.file_name_regex' do
- subject { described_class.file_name_regex }
-
- it { is_expected.to match('foo@bar') }
- end
-
describe '.environment_slug_regex' do
subject { described_class.environment_name_regex }
@@ -44,4 +38,15 @@ describe Gitlab::Regex, lib: true do
it { is_expected.not_to match('9foo') }
it { is_expected.not_to match('foo-') }
end
+
+ describe '.container_repository_name_regex' do
+ subject { described_class.container_repository_name_regex }
+
+ it { is_expected.to match('image') }
+ it { is_expected.to match('my/image') }
+ it { is_expected.to match('my/awesome/image-1') }
+ it { is_expected.to match('my/awesome/image.test') }
+ it { is_expected.not_to match('.my/image') }
+ it { is_expected.not_to match('my/image.') }
+ end
end
diff --git a/spec/lib/gitlab/request_context_spec.rb b/spec/lib/gitlab/request_context_spec.rb
index a91c8655cdd..e272bdb9284 100644
--- a/spec/lib/gitlab/request_context_spec.rb
+++ b/spec/lib/gitlab/request_context_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Gitlab::RequestContext, lib: true do
+describe Gitlab::RequestContext do
describe '#client_ip' do
- subject { Gitlab::RequestContext.client_ip }
+ subject { described_class.client_ip }
let(:app) { -> (env) {} }
let(:env) { Hash.new }
@@ -16,7 +16,7 @@ describe Gitlab::RequestContext, lib: true do
before do
allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip)
- Gitlab::RequestContext.new(app).call(env)
+ described_class.new(app).call(env)
end
it { is_expected.to eq(ip) }
diff --git a/spec/lib/gitlab/request_forgery_protection_spec.rb b/spec/lib/gitlab/request_forgery_protection_spec.rb
new file mode 100644
index 00000000000..305de613866
--- /dev/null
+++ b/spec/lib/gitlab/request_forgery_protection_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+describe Gitlab::RequestForgeryProtection, :allow_forgery_protection do
+ let(:csrf_token) { SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) }
+ let(:env) do
+ {
+ 'rack.input' => '',
+ 'rack.session' => {
+ _csrf_token: csrf_token
+ }
+ }
+ end
+
+ describe '.call' do
+ context 'when the request method is GET' do
+ before do
+ env['REQUEST_METHOD'] = 'GET'
+ end
+
+ it 'does not raise an exception' do
+ expect { described_class.call(env) }.not_to raise_exception
+ end
+ end
+
+ context 'when the request method is POST' do
+ before do
+ env['REQUEST_METHOD'] = 'POST'
+ end
+
+ context 'when the CSRF token is valid' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = csrf_token
+ end
+
+ it 'does not raise an exception' do
+ expect { described_class.call(env) }.not_to raise_exception
+ end
+ end
+
+ context 'when the CSRF token is invalid' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = 'foo'
+ end
+
+ it 'raises an ActionController::InvalidAuthenticityToken exception' do
+ expect { described_class.call(env) }.to raise_exception(ActionController::InvalidAuthenticityToken)
+ end
+ end
+ end
+ end
+
+ describe '.verified?' do
+ context 'when the request method is GET' do
+ before do
+ env['REQUEST_METHOD'] = 'GET'
+ end
+
+ it 'returns true' do
+ expect(described_class.verified?(env)).to be_truthy
+ end
+ end
+
+ context 'when the request method is POST' do
+ before do
+ env['REQUEST_METHOD'] = 'POST'
+ end
+
+ context 'when the CSRF token is valid' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = csrf_token
+ end
+
+ it 'returns true' do
+ expect(described_class.verified?(env)).to be_truthy
+ end
+ end
+
+ context 'when the CSRF token is invalid' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = 'foo'
+ end
+
+ it 'returns false' do
+ expect(described_class.verified?(env)).to be_falsey
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/request_profiler_spec.rb b/spec/lib/gitlab/request_profiler_spec.rb
index ae9c06ebb7d..fd8cbf39bce 100644
--- a/spec/lib/gitlab/request_profiler_spec.rb
+++ b/spec/lib/gitlab/request_profiler_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::RequestProfiler, lib: true do
+describe Gitlab::RequestProfiler do
describe '.profile_token' do
it 'returns a token' do
expect(described_class.profile_token).to be_present
diff --git a/spec/lib/gitlab/route_map_spec.rb b/spec/lib/gitlab/route_map_spec.rb
index 21c00c6e5b8..d672f7b5675 100644
--- a/spec/lib/gitlab/route_map_spec.rb
+++ b/spec/lib/gitlab/route_map_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::RouteMap, lib: true do
+describe Gitlab::RouteMap do
describe '#initialize' do
context 'when the data is not YAML' do
it 'raises an error' do
@@ -55,6 +55,19 @@ describe Gitlab::RouteMap, lib: true do
end
describe '#public_path_for_source_path' do
+ context 'malicious regexp' do
+ include_examples 'malicious regexp'
+
+ subject do
+ map = described_class.new(<<-"MAP".strip_heredoc)
+ - source: '#{malicious_regexp}'
+ public: '/'
+ MAP
+
+ map.public_path_for_source_path(malicious_text)
+ end
+ end
+
subject do
described_class.new(<<-'MAP'.strip_heredoc)
# Team data
diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb
index a4d2367b72a..2827a18515e 100644
--- a/spec/lib/gitlab/saml/user_spec.rb
+++ b/spec/lib/gitlab/saml/user_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Saml::User, lib: true do
+describe Gitlab::Saml::User do
let(:saml_user) { described_class.new(auth_hash) }
let(:gl_user) { saml_user.gl_user }
let(:uid) { 'my-uid' }
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index a97a0f8452b..b90d8dede0f 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -1,9 +1,10 @@
require 'spec_helper'
require 'stringio'
-describe Gitlab::Shell, lib: true do
+describe Gitlab::Shell do
let(:project) { double('Project', id: 7, path: 'diaspora') }
- let(:gitlab_shell) { Gitlab::Shell.new }
+ let(:gitlab_shell) { described_class.new }
+ let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } }
before do
allow(Project).to receive(:find).and_return(project)
@@ -29,7 +30,7 @@ describe Gitlab::Shell, lib: true do
allow(Gitlab.config.gitlab_shell).to receive(:secret_file).and_return(secret_file)
allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-secret-test')
FileUtils.mkdir('tmp/tests/shell-secret-test')
- Gitlab::Shell.ensure_secret_token!
+ described_class.ensure_secret_token!
end
after do
@@ -38,7 +39,7 @@ describe Gitlab::Shell, lib: true do
end
it 'creates and links the secret token file' do
- secret_token = Gitlab::Shell.secret_token
+ secret_token = described_class.secret_token
expect(File.exist?(secret_file)).to be(true)
expect(File.read(secret_file).chomp).to eq(secret_token)
@@ -50,7 +51,7 @@ describe Gitlab::Shell, lib: true do
describe '#add_key' do
it 'removes trailing garbage' do
allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(Gitlab::Utils).to receive(:system_silent).with(
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
[:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
)
@@ -58,7 +59,7 @@ describe Gitlab::Shell, lib: true do
end
end
- describe Gitlab::Shell::KeyAdder, lib: true do
+ describe Gitlab::Shell::KeyAdder do
describe '#add_key' do
it 'removes trailing garbage' do
io = spy(:io)
@@ -100,17 +101,91 @@ describe Gitlab::Shell, lib: true do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end
+ describe '#add_repository' do
+ it 'returns true when the command succeeds' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'add-project', 'current/storage', 'project/path.git'],
+ nil, popen_vars).and_return([nil, 0])
+
+ expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be true
+ end
+
+ it 'returns false when the command fails' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'add-project', 'current/storage', 'project/path.git'],
+ nil, popen_vars).and_return(["error", 1])
+
+ expect(gitlab_shell.add_repository('current/storage', 'project/path')).to be false
+ end
+ end
+
+ describe '#remove_repository' do
+ it 'returns true when the command succeeds' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
+ nil, popen_vars).and_return([nil, 0])
+
+ expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be true
+ end
+
+ it 'returns false when the command fails' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
+ nil, popen_vars).and_return(["error", 1])
+
+ expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be false
+ end
+ end
+
+ describe '#mv_repository' do
+ it 'returns true when the command succeeds' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
+ nil, popen_vars).and_return([nil, 0])
+
+ expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be true
+ end
+
+ it 'returns false when the command fails' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
+ nil, popen_vars).and_return(["error", 1])
+
+ expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be false
+ end
+ end
+
+ describe '#fork_repository' do
+ it 'returns true when the command succeeds' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
+ nil, popen_vars).and_return([nil, 0])
+
+ expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be true
+ end
+
+ it 'return false when the command fails' do
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
+ nil, popen_vars).and_return(["error", 1])
+
+ expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be false
+ end
+ end
+
describe '#fetch_remote' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800']).and_return([nil, 0])
+ .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'],
+ nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage')).to be true
end
it 'raises an exception when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800']).and_return(["error", 1])
+ .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'],
+ nil, popen_vars).and_return(["error", 1])
expect { gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage') }.to raise_error(Gitlab::Shell::Error, "error")
end
@@ -119,14 +194,16 @@ describe Gitlab::Shell, lib: true do
describe '#import_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"]).and_return([nil, 0])
+ .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
+ nil, popen_vars).and_return([nil, 0])
expect(gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git')).to be true
end
it 'raises an exception when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"]).and_return(["error", 1])
+ .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
+ nil, popen_vars).and_return(["error", 1])
expect { gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git') }.to raise_error(Gitlab::Shell::Error, "error")
end
diff --git a/spec/lib/gitlab/sherlock/collection_spec.rb b/spec/lib/gitlab/sherlock/collection_spec.rb
index 2ae79b50e77..873ed14f804 100644
--- a/spec/lib/gitlab/sherlock/collection_spec.rb
+++ b/spec/lib/gitlab/sherlock/collection_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Collection, lib: true do
+describe Gitlab::Sherlock::Collection do
let(:collection) { described_class.new }
let(:transaction) do
diff --git a/spec/lib/gitlab/sherlock/file_sample_spec.rb b/spec/lib/gitlab/sherlock/file_sample_spec.rb
index 4989d14def3..394421504e0 100644
--- a/spec/lib/gitlab/sherlock/file_sample_spec.rb
+++ b/spec/lib/gitlab/sherlock/file_sample_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::FileSample, lib: true do
+describe Gitlab::Sherlock::FileSample do
let(:sample) { described_class.new(__FILE__, [], 150.4, 2) }
describe '#id' do
diff --git a/spec/lib/gitlab/sherlock/line_profiler_spec.rb b/spec/lib/gitlab/sherlock/line_profiler_spec.rb
index 39c6b2a4844..f2f8040fa0b 100644
--- a/spec/lib/gitlab/sherlock/line_profiler_spec.rb
+++ b/spec/lib/gitlab/sherlock/line_profiler_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::LineProfiler, lib: true do
+describe Gitlab::Sherlock::LineProfiler do
let(:profiler) { described_class.new }
describe '#profile' do
diff --git a/spec/lib/gitlab/sherlock/line_sample_spec.rb b/spec/lib/gitlab/sherlock/line_sample_spec.rb
index f9b61f8684e..5f02f6a3213 100644
--- a/spec/lib/gitlab/sherlock/line_sample_spec.rb
+++ b/spec/lib/gitlab/sherlock/line_sample_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::LineSample, lib: true do
+describe Gitlab::Sherlock::LineSample do
let(:sample) { described_class.new(150.0, 4) }
describe '#duration' do
diff --git a/spec/lib/gitlab/sherlock/location_spec.rb b/spec/lib/gitlab/sherlock/location_spec.rb
index 5739afa6b1e..b295a624b35 100644
--- a/spec/lib/gitlab/sherlock/location_spec.rb
+++ b/spec/lib/gitlab/sherlock/location_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Location, lib: true do
+describe Gitlab::Sherlock::Location do
let(:location) { described_class.new(__FILE__, 1) }
describe 'from_ruby_location' do
diff --git a/spec/lib/gitlab/sherlock/middleware_spec.rb b/spec/lib/gitlab/sherlock/middleware_spec.rb
index b98ab0b14a2..2016023df06 100644
--- a/spec/lib/gitlab/sherlock/middleware_spec.rb
+++ b/spec/lib/gitlab/sherlock/middleware_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Middleware, lib: true do
+describe Gitlab::Sherlock::Middleware do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
diff --git a/spec/lib/gitlab/sherlock/query_spec.rb b/spec/lib/gitlab/sherlock/query_spec.rb
index d97b5eef573..426071c7f92 100644
--- a/spec/lib/gitlab/sherlock/query_spec.rb
+++ b/spec/lib/gitlab/sherlock/query_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Query, lib: true do
+describe Gitlab::Sherlock::Query do
let(:started_at) { Time.utc(2015, 1, 1) }
let(:finished_at) { started_at + 5 }
diff --git a/spec/lib/gitlab/sherlock/transaction_spec.rb b/spec/lib/gitlab/sherlock/transaction_spec.rb
index 6ae1aa20ea7..4a14dfbec56 100644
--- a/spec/lib/gitlab/sherlock/transaction_spec.rb
+++ b/spec/lib/gitlab/sherlock/transaction_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Transaction, lib: true do
+describe Gitlab::Sherlock::Transaction do
let(:transaction) { described_class.new('POST', '/cat_pictures') }
describe '#id' do
diff --git a/spec/lib/gitlab/sidekiq_status_spec.rb b/spec/lib/gitlab/sidekiq_status_spec.rb
index 496e50fbae4..c2e77ef6b6c 100644
--- a/spec/lib/gitlab/sidekiq_status_spec.rb
+++ b/spec/lib/gitlab/sidekiq_status_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::SidekiqStatus do
- describe '.set', :redis do
+ describe '.set', :clean_gitlab_redis_shared_state do
it 'stores the job ID' do
described_class.set('123')
@@ -14,7 +14,7 @@ describe Gitlab::SidekiqStatus do
end
end
- describe '.unset', :redis do
+ describe '.unset', :clean_gitlab_redis_shared_state do
it 'removes the job ID' do
described_class.set('123')
described_class.unset('123')
@@ -27,7 +27,7 @@ describe Gitlab::SidekiqStatus do
end
end
- describe '.all_completed?', :redis do
+ describe '.all_completed?', :clean_gitlab_redis_shared_state do
it 'returns true if all jobs have been completed' do
expect(described_class.all_completed?(%w(123))).to eq(true)
end
@@ -39,7 +39,7 @@ describe Gitlab::SidekiqStatus do
end
end
- describe '.num_running', :redis do
+ describe '.num_running', :clean_gitlab_redis_shared_state do
it 'returns 0 if all jobs have been completed' do
expect(described_class.num_running(%w(123))).to eq(0)
end
@@ -52,7 +52,7 @@ describe Gitlab::SidekiqStatus do
end
end
- describe '.num_completed', :redis do
+ describe '.num_completed', :clean_gitlab_redis_shared_state do
it 'returns 1 if all jobs have been completed' do
expect(described_class.num_completed(%w(123))).to eq(1)
end
@@ -74,7 +74,7 @@ describe Gitlab::SidekiqStatus do
end
end
- describe 'completed', :redis do
+ describe 'completed', :clean_gitlab_redis_shared_state do
it 'returns the completed job' do
expect(described_class.completed_jids(%w(123))).to eq(['123'])
end
diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb
index 28d7f9858c3..88f73bf90cd 100644
--- a/spec/lib/gitlab/slash_commands/command_spec.rb
+++ b/spec/lib/gitlab/slash_commands/command_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::Command, service: true do
+describe Gitlab::SlashCommands::Command do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -80,7 +80,7 @@ describe Gitlab::SlashCommands::Command, service: true do
it 'returns error' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to include('Too many actions defined')
+ expect(subject[:text]).to include("Couldn't find a deployment manual action.")
end
end
end
diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb
index d919f7260db..c3fb7d5adea 100644
--- a/spec/lib/gitlab/slash_commands/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::Deploy, service: true do
+describe Gitlab::SlashCommands::Deploy do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -22,7 +22,7 @@ describe Gitlab::SlashCommands::Deploy, service: true do
context 'if no environment is defined' do
it 'does not execute an action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("No action found to be executed")
+ expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
@@ -35,12 +35,12 @@ describe Gitlab::SlashCommands::Deploy, service: true do
context 'without actions' do
it 'does not execute an action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("No action found to be executed")
+ expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
- context 'with action' do
- let!(:manual1) do
+ context 'when single action has been matched' do
+ before do
create(:ci_build, :manual, pipeline: pipeline,
name: 'first',
environment: 'production')
@@ -48,31 +48,61 @@ describe Gitlab::SlashCommands::Deploy, service: true do
it 'returns success result' do
expect(subject[:response_type]).to be(:in_channel)
- expect(subject[:text]).to start_with('Deployment started from staging to production')
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
end
+ end
+
+ context 'when more than one action has been matched' do
+ context 'when there is no specific actions with a environment name' do
+ before do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
- context 'when duplicate action exists' do
- let!(:manual2) do
create(:ci_build, :manual, pipeline: pipeline,
name: 'second',
environment: 'production')
end
- it 'returns error' do
+ it 'returns error about too many actions defined' do
+ expect(subject[:text]).to eq("Couldn't find a deployment manual action.")
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq('Too many actions defined')
end
end
- context 'when teardown action exists' do
- let!(:teardown) do
+ context 'when one of the actions is environement specific action' do
+ before do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
+
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'production',
+ environment: 'production')
+ end
+
+ it 'deploys to production' do
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
+ expect(subject[:response_type]).to be(:in_channel)
+ end
+ end
+
+ context 'when one of the actions is a teardown action' do
+ before do
+ create(:ci_build, :manual, pipeline: pipeline,
+ name: 'first',
+ environment: 'production')
+
create(:ci_build, :manual, :teardown_environment,
pipeline: pipeline, name: 'teardown', environment: 'production')
end
- it 'returns the success message' do
+ it 'deploys to production' do
+ expect(subject[:text])
+ .to start_with('Deployment started from staging to production')
expect(subject[:response_type]).to be(:in_channel)
- expect(subject[:text]).to start_with('Deployment started from staging to production')
end
end
end
diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
index 4de50d4a8bb..5dfb1b506bc 100644
--- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::IssueNew, service: true do
+describe Gitlab::SlashCommands::IssueNew do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
index 06fff0afc50..e5409fe2339 100644
--- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::IssueSearch, service: true do
+describe Gitlab::SlashCommands::IssueSearch do
describe '#execute' do
let!(:issue) { create(:issue, project: project, title: 'find me') }
let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
index 1899f664ccd..f67a17c7922 100644
--- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SlashCommands::IssueShow, service: true do
+describe Gitlab::SlashCommands::IssueShow do
describe '#execute' do
let(:issue) { create(:issue, project: project) }
let(:project) { create(:empty_project) }
diff --git a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
index dee3c77db27..d16d122c64e 100644
--- a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
+++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb
@@ -17,8 +17,8 @@ describe Gitlab::SlashCommands::Presenters::Deploy do
end
end
- describe '#no_actions' do
- subject { described_class.new(nil).no_actions }
+ describe '#action_not_found' do
+ subject { described_class.new(nil).action_not_found }
it { is_expected.to have_key(:text) }
it { is_expected.to have_key(:response_type) }
@@ -27,21 +27,7 @@ describe Gitlab::SlashCommands::Presenters::Deploy do
it 'tells the user there is no action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("No action found to be executed")
- end
- end
-
- describe '#too_many_actions' do
- subject { described_class.new([]).too_many_actions }
-
- it { is_expected.to have_key(:text) }
- it { is_expected.to have_key(:response_type) }
- it { is_expected.to have_key(:status) }
- it { is_expected.not_to have_key(:attachments) }
-
- it 'tells the user there is no action' do
- expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to eq("Too many actions defined")
+ expect(subject[:text]).to eq "Couldn't find a deployment manual action."
end
end
end
diff --git a/spec/lib/gitlab/sql/glob_spec.rb b/spec/lib/gitlab/sql/glob_spec.rb
new file mode 100644
index 00000000000..f0bb4294d62
--- /dev/null
+++ b/spec/lib/gitlab/sql/glob_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe Gitlab::SQL::Glob do
+ describe '.to_like' do
+ it 'matches * as %' do
+ expect(glob('apple', '*')).to be(true)
+ expect(glob('apple', 'app*')).to be(true)
+ expect(glob('apple', 'apple*')).to be(true)
+ expect(glob('apple', '*pple')).to be(true)
+ expect(glob('apple', 'ap*le')).to be(true)
+
+ expect(glob('apple', '*a')).to be(false)
+ expect(glob('apple', 'app*a')).to be(false)
+ expect(glob('apple', 'ap*l')).to be(false)
+ end
+
+ it 'matches % literally' do
+ expect(glob('100%', '100%')).to be(true)
+
+ expect(glob('100%', '%')).to be(false)
+ end
+
+ it 'matches _ literally' do
+ expect(glob('^_^', '^_^')).to be(true)
+
+ expect(glob('^A^', '^_^')).to be(false)
+ end
+ end
+
+ def glob(string, pattern)
+ match(string, subject.to_like(quote(pattern)))
+ end
+
+ def match(string, pattern)
+ value = query("SELECT #{quote(string)} LIKE #{pattern}")
+ .rows.flatten.first
+
+ case value
+ when 't', 1
+ true
+ else
+ false
+ end
+ end
+
+ def query(sql)
+ ActiveRecord::Base.connection.select_all(sql)
+ end
+
+ def quote(string)
+ ActiveRecord::Base.connection.quote(string)
+ end
+end
diff --git a/spec/lib/gitlab/sql/union_spec.rb b/spec/lib/gitlab/sql/union_spec.rb
index 849edb09476..5346881444d 100644
--- a/spec/lib/gitlab/sql/union_spec.rb
+++ b/spec/lib/gitlab/sql/union_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SQL::Union, lib: true do
+describe Gitlab::SQL::Union do
let(:relation_1) { User.where(email: 'alice@example.com').select(:id) }
let(:relation_2) { User.where(email: 'bob@example.com').select(:id) }
diff --git a/spec/lib/gitlab/string_range_marker_spec.rb b/spec/lib/gitlab/string_range_marker_spec.rb
index 7c77772b3f6..abeaa7f0ddb 100644
--- a/spec/lib/gitlab/string_range_marker_spec.rb
+++ b/spec/lib/gitlab/string_range_marker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::StringRangeMarker, lib: true do
+describe Gitlab::StringRangeMarker do
describe '#mark' do
context "when the rich text is html safe" do
let(:raw) { "abc <def>" }
diff --git a/spec/lib/gitlab/string_regex_marker_spec.rb b/spec/lib/gitlab/string_regex_marker_spec.rb
index 2f5cf6c6e3b..d715f9bd641 100644
--- a/spec/lib/gitlab/string_regex_marker_spec.rb
+++ b/spec/lib/gitlab/string_regex_marker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::StringRegexMarker, lib: true do
+describe Gitlab::StringRegexMarker do
describe '#mark' do
let(:raw) { %{"name": "AFNetworking"} }
let(:rich) { %{<span class="key">"name"</span><span class="punctuation">: </span><span class="value">"AFNetworking"</span>}.html_safe }
diff --git a/spec/lib/gitlab/untrusted_regexp_spec.rb b/spec/lib/gitlab/untrusted_regexp_spec.rb
new file mode 100644
index 00000000000..bed58d407ef
--- /dev/null
+++ b/spec/lib/gitlab/untrusted_regexp_spec.rb
@@ -0,0 +1,98 @@
+require 'spec_helper'
+
+describe Gitlab::UntrustedRegexp do
+ describe '#initialize' do
+ subject { described_class.new(pattern) }
+
+ context 'invalid regexp' do
+ let(:pattern) { '[' }
+
+ it { expect { subject }.to raise_error(RegexpError) }
+ end
+ end
+
+ describe '#replace_all' do
+ it 'replaces all instances of the match in a string' do
+ result = described_class.new('foo').replace_all('foo bar foo', 'oof')
+
+ expect(result).to eq('oof bar oof')
+ end
+ end
+
+ describe '#replace' do
+ it 'replaces the first instance of the match in a string' do
+ result = described_class.new('foo').replace('foo bar foo', 'oof')
+
+ expect(result).to eq('oof bar foo')
+ end
+ end
+
+ describe '#===' do
+ it 'returns true for a match' do
+ result = described_class.new('foo') === 'a foo here'
+
+ expect(result).to be_truthy
+ end
+
+ it 'returns false for no match' do
+ result = described_class.new('foo') === 'a bar here'
+
+ expect(result).to be_falsy
+ end
+ end
+
+ describe '#scan' do
+ subject { described_class.new(regexp).scan(text) }
+ context 'malicious regexp' do
+ let(:text) { malicious_text }
+ let(:regexp) { malicious_regexp }
+
+ include_examples 'malicious regexp'
+ end
+
+ context 'empty regexp' do
+ let(:regexp) { '' }
+ let(:text) { 'foo' }
+
+ it 'returns an array of nil matches' do
+ is_expected.to eq([nil, nil, nil, nil])
+ end
+ end
+
+ context 'empty capture group regexp' do
+ let(:regexp) { '()' }
+ let(:text) { 'foo' }
+
+ it 'returns an array of nil matches in an array' do
+ is_expected.to eq([[nil], [nil], [nil], [nil]])
+ end
+ end
+
+ context 'no capture group' do
+ let(:regexp) { '.+' }
+ let(:text) { 'foo' }
+
+ it 'returns the whole match' do
+ is_expected.to eq(['foo'])
+ end
+ end
+
+ context 'one capture group' do
+ let(:regexp) { '(f).+' }
+ let(:text) { 'foo' }
+
+ it 'returns the captured part' do
+ is_expected.to eq([%w[f]])
+ end
+ end
+
+ context 'two capture groups' do
+ let(:regexp) { '(f).(o)' }
+ let(:text) { 'foo' }
+
+ it 'returns the captured parts' do
+ is_expected.to eq([%w[f o]])
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb
index fcfd8d58b70..6106f13c774 100644
--- a/spec/lib/gitlab/upgrader_spec.rb
+++ b/spec/lib/gitlab/upgrader_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::Upgrader, lib: true do
- let(:upgrader) { Gitlab::Upgrader.new }
+describe Gitlab::Upgrader do
+ let(:upgrader) { described_class.new }
let(:current_version) { Gitlab::VERSION }
describe 'current_version_raw' do
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index a504d299307..f5b4882815f 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::UrlBlocker, lib: true do
+describe Gitlab::UrlBlocker do
describe '#blocked_url?' do
it 'allows imports from configured web host and port' do
import_url = "http://#{Gitlab.config.gitlab.host}:#{Gitlab.config.gitlab.port}/t.git"
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index e9a6e273516..50422020823 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::UrlBuilder, lib: true do
+describe Gitlab::UrlBuilder do
describe '.build' do
context 'when passing a Commit' do
it 'returns a proper URL' do
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 6bce724a3f6..308b1a128be 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::UrlSanitizer, lib: true do
+describe Gitlab::UrlSanitizer do
let(:credentials) { { user: 'blah', password: 'password' } }
let(:url_sanitizer) do
described_class.new("https://github.com/me/project.git", credentials: credentials)
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index b47e1b56fa9..68429d792f2 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -1,11 +1,19 @@
require 'spec_helper'
describe Gitlab::UsageData do
- let!(:project) { create(:empty_project) }
- let!(:project2) { create(:empty_project) }
- let!(:board) { create(:board, project: project) }
+ let(:projects) { create_list(:project, 3) }
+ let!(:board) { create(:board, project: projects[0]) }
describe '#data' do
+ before do
+ create(:jira_service, project: projects[0])
+ create(:jira_service, project: projects[1])
+ create(:prometheus_service, project: projects[1])
+ create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true)
+ create(:service, project: projects[1], type: 'SlackService', active: true)
+ create(:service, project: projects[2], type: 'SlackService', active: true)
+ end
+
subject { described_class.data }
it "gathers usage data" do
@@ -25,18 +33,20 @@ describe Gitlab::UsageData do
count_data = subject[:counts]
expect(count_data[:boards]).to eq(1)
- expect(count_data[:projects]).to eq(2)
+ expect(count_data[:projects]).to eq(3)
expect(count_data.keys).to match_array(%i(
boards
ci_builds
- ci_pipelines
+ ci_internal_pipelines
+ ci_external_pipelines
ci_runners
ci_triggers
ci_pipeline_schedules
deploy_keys
deployments
environments
+ in_review_folder
groups
issues
keys
@@ -46,6 +56,10 @@ describe Gitlab::UsageData do
milestones
notes
projects
+ projects_imported_from_github
+ projects_jira_active
+ projects_slack_notifications_active
+ projects_slack_slash_active
projects_prometheus_active
pages_domains
protected_branches
@@ -56,6 +70,16 @@ describe Gitlab::UsageData do
web_hooks
))
end
+
+ it 'gathers projects data correctly' do
+ count_data = subject[:counts]
+
+ expect(count_data[:projects]).to eq(3)
+ expect(count_data[:projects_prometheus_active]).to eq(1)
+ expect(count_data[:projects_jira_active]).to eq(2)
+ expect(count_data[:projects_slack_notifications_active]).to eq(2)
+ expect(count_data[:projects_slack_slash_active]).to eq(1)
+ end
end
describe '#license_usage_data' do
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 0d87cf25dbb..5ebaf6c1507 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Gitlab::UserAccess, lib: true do
- let(:access) { Gitlab::UserAccess.new(user, project: project) }
+describe Gitlab::UserAccess do
+ let(:access) { described_class.new(user, project: project) }
let(:project) { create(:project) }
let(:user) { create(:user) }
@@ -28,7 +28,7 @@ describe Gitlab::UserAccess, lib: true do
describe 'push to empty project' do
let(:empty_project) { create(:project_empty_repo) }
- let(:project_access) { Gitlab::UserAccess.new(user, project: empty_project) }
+ let(:project_access) { described_class.new(user, project: empty_project) }
it 'returns true if user is master' do
empty_project.team << [user, :master]
diff --git a/spec/lib/gitlab/user_activities_spec.rb b/spec/lib/gitlab/user_activities_spec.rb
index 187d88c8c58..6bce2ee13cf 100644
--- a/spec/lib/gitlab/user_activities_spec.rb
+++ b/spec/lib/gitlab/user_activities_spec.rb
@@ -1,27 +1,27 @@
require 'spec_helper'
-describe Gitlab::UserActivities, :redis, lib: true do
+describe Gitlab::UserActivities, :clean_gitlab_redis_shared_state do
let(:now) { Time.now }
describe '.record' do
context 'with no time given' do
- it 'uses Time.now and records an activity in Redis' do
+ it 'uses Time.now and records an activity in SharedState' do
Timecop.freeze do
now # eager-load now
described_class.record(42)
end
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]])
end
end
end
context 'with a time given' do
- it 'uses the given time and records an activity in Redis' do
+ it 'uses the given time and records an activity in SharedState' do
described_class.record(42, now)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]])
end
end
@@ -31,30 +31,30 @@ describe Gitlab::UserActivities, :redis, lib: true do
describe '.delete' do
context 'with a single key' do
context 'and key exists' do
- it 'removes the pair from Redis' do
+ it 'removes the pair from SharedState' do
described_class.record(42, now)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]])
end
subject.delete(42)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []])
end
end
end
context 'and key does not exist' do
- it 'removes the pair from Redis' do
- Gitlab::Redis.with do |redis|
+ it 'removes the pair from SharedState' do
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []])
end
subject.delete(42)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []])
end
end
@@ -63,33 +63,33 @@ describe Gitlab::UserActivities, :redis, lib: true do
context 'with multiple keys' do
context 'and all keys exist' do
- it 'removes the pair from Redis' do
+ it 'removes the pair from SharedState' do
described_class.record(41, now)
described_class.record(42, now)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['41', now.to_i.to_s], ['42', now.to_i.to_s]]])
end
subject.delete(41, 42)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []])
end
end
end
context 'and some keys does not exist' do
- it 'removes the existing pair from Redis' do
+ it 'removes the existing pair from SharedState' do
described_class.record(42, now)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', [['42', now.to_i.to_s]]])
end
subject.delete(41, 42)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
expect(redis.hscan(described_class::KEY, 0)).to eq(['0', []])
end
end
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index 00941aec380..111c873f79c 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Utils, lib: true do
+describe Gitlab::Utils do
delegate :to_boolean, :boolean_to_yes_no, to: :described_class
describe '.to_boolean' do
diff --git a/spec/lib/gitlab/version_info_spec.rb b/spec/lib/gitlab/version_info_spec.rb
index 706ee9bec58..e7e1a92ae54 100644
--- a/spec/lib/gitlab/version_info_spec.rb
+++ b/spec/lib/gitlab/version_info_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::VersionInfo', lib: true, no_db: true do
+describe 'Gitlab::VersionInfo' do
before do
@unknown = Gitlab::VersionInfo.new
@v0_0_1 = Gitlab::VersionInfo.new(0, 0, 1)
diff --git a/spec/lib/gitlab/visibility_level_spec.rb b/spec/lib/gitlab/visibility_level_spec.rb
index 84d2484cc8a..48a67773de9 100644
--- a/spec/lib/gitlab/visibility_level_spec.rb
+++ b/spec/lib/gitlab/visibility_level_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::VisibilityLevel, lib: true do
+describe Gitlab::VisibilityLevel do
describe '.level_value' do
it 'converts "public" to integer value' do
expect(described_class.level_value('public')).to eq(Gitlab::VisibilityLevel::PUBLIC)
@@ -21,7 +21,7 @@ describe Gitlab::VisibilityLevel, lib: true do
describe '.levels_for_user' do
it 'returns all levels for an admin' do
- user = double(:user, admin?: true)
+ user = build(:user, :admin)
expect(described_class.levels_for_user(user))
.to eq([Gitlab::VisibilityLevel::PRIVATE,
@@ -30,7 +30,7 @@ describe Gitlab::VisibilityLevel, lib: true do
end
it 'returns INTERNAL and PUBLIC for internal users' do
- user = double(:user, admin?: false, external?: false)
+ user = build(:user)
expect(described_class.levels_for_user(user))
.to eq([Gitlab::VisibilityLevel::INTERNAL,
@@ -38,7 +38,7 @@ describe Gitlab::VisibilityLevel, lib: true do
end
it 'returns PUBLIC for external users' do
- user = double(:user, admin?: false, external?: true)
+ user = build(:user, :external)
expect(described_class.levels_for_user(user))
.to eq([Gitlab::VisibilityLevel::PUBLIC])
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index a3e8166cb70..654397ccffb 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Workhorse, lib: true do
+describe Gitlab::Workhorse do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
@@ -63,13 +63,13 @@ describe Gitlab::Workhorse, lib: true do
end
context 'without ca_pem' do
- subject { Gitlab::Workhorse.terminal_websocket(terminal) }
+ subject { described_class.terminal_websocket(terminal) }
it { is_expected.to eq(workhorse) }
end
context 'with ca_pem' do
- subject { Gitlab::Workhorse.terminal_websocket(terminal(ca_pem: "foo")) }
+ subject { described_class.terminal_websocket(terminal(ca_pem: "foo")) }
it { is_expected.to eq(workhorse(ca_pem: "foo")) }
end
@@ -216,7 +216,6 @@ describe Gitlab::Workhorse, lib: true do
it 'includes a Repository param' do
repo_param = { Repository: {
- path: '', # deprecated field; grpc automatically creates it anyway
storage_name: 'default',
relative_path: project.full_path + '.git'
} }
@@ -238,7 +237,8 @@ describe Gitlab::Workhorse, lib: true do
context 'when action is not enabled by feature flag' do
it 'does not include Gitaly params in the returned value' do
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag).and_return(false)
+ status_opt_out = Gitlab::GitalyClient::MigrationStatus::OPT_OUT
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag, status: status_opt_out).and_return(false)
expect(subject).not_to include(gitaly_params)
end
@@ -277,7 +277,7 @@ describe Gitlab::Workhorse, lib: true do
end
it 'set and notify' do
- expect_any_instance_of(Redis).to receive(:publish)
+ expect_any_instance_of(::Redis).to receive(:publish)
.with(described_class::NOTIFICATION_CHANNEL, "test-key=test-value")
subject
@@ -311,11 +311,49 @@ describe Gitlab::Workhorse, lib: true do
end
it 'does not notify' do
- expect_any_instance_of(Redis).not_to receive(:publish)
+ expect_any_instance_of(::Redis).not_to receive(:publish)
subject
end
end
end
end
+
+ describe '.send_git_blob' do
+ include FakeBlobHelpers
+
+ let(:blob) { fake_blob }
+
+ subject { described_class.send_git_blob(repository, blob) }
+
+ context 'when Gitaly workhorse_raw_show feature is enabled' do
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(subject)
+
+ expect(key).to eq('Gitlab-Workhorse-Send-Data')
+ expect(command).to eq('git-blob')
+ expect(params).to eq({
+ 'GitalyServer' => {
+ address: Gitlab::GitalyClient.address(project.repository_storage),
+ token: Gitlab::GitalyClient.token(project.repository_storage)
+ },
+ 'GetBlobRequest' => {
+ repository: repository.gitaly_repository.to_h,
+ oid: blob.id,
+ limit: -1
+ }
+ }.deep_stringify_keys)
+ end
+ end
+
+ context 'when Gitaly workhorse_raw_show feature is disabled', skip_gitaly_mock: true do
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(subject)
+
+ expect(key).to eq('Gitlab-Workhorse-Send-Data')
+ expect(command).to eq('git-blob')
+ expect(params).to eq('RepoPath' => repository.path_to_repo, 'BlobId' => blob.id)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index c4c107c9eea..f97136f0191 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Gitlab, lib: true do
+describe Gitlab do
describe '.com?' do
it 'is true when on GitLab.com' do
stub_config_setting(url: 'https://gitlab.com')
diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb
index 5892f3481a4..0c15ba22bf2 100644
--- a/spec/lib/repository_cache_spec.rb
+++ b/spec/lib/repository_cache_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe RepositoryCache, lib: true do
+describe RepositoryCache do
let(:project) { create(:empty_project) }
let(:backend) { double('backend').as_null_object }
- let(:cache) { RepositoryCache.new('example', project.id, backend) }
+ let(:cache) { described_class.new('example', project.id, backend) }
describe '#cache_key' do
it 'includes the namespace' do
diff --git a/spec/lib/system_check/simple_executor_spec.rb b/spec/lib/system_check/simple_executor_spec.rb
index a5c6170cd7d..025ea2673b4 100644
--- a/spec/lib/system_check/simple_executor_spec.rb
+++ b/spec/lib/system_check/simple_executor_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'rake_helper'
-describe SystemCheck::SimpleExecutor, lib: true do
+describe SystemCheck::SimpleExecutor do
class SimpleCheck < SystemCheck::BaseCheck
set_name 'my simple check'
@@ -75,6 +75,24 @@ describe SystemCheck::SimpleExecutor, lib: true do
end
end
+ class BugousCheck < SystemCheck::BaseCheck
+ CustomError = Class.new(StandardError)
+ set_name 'my bugous check'
+
+ def check?
+ raise CustomError, 'omg'
+ end
+ end
+
+ before do
+ @rainbow = Rainbow.enabled
+ Rainbow.enabled = false
+ end
+
+ after do
+ Rainbow.enabled = @rainbow
+ end
+
describe '#component' do
it 'returns stored component name' do
expect(subject.component).to eq('Test')
@@ -219,5 +237,11 @@ describe SystemCheck::SimpleExecutor, lib: true do
end
end
end
+
+ context 'when there is an exception' do
+ it 'rescues the exception' do
+ expect{ subject.run_check(BugousCheck) }.not_to raise_exception
+ end
+ end
end
end
diff --git a/spec/lib/system_check_spec.rb b/spec/lib/system_check_spec.rb
index 23d9beddb08..4d9e17fa6ec 100644
--- a/spec/lib/system_check_spec.rb
+++ b/spec/lib/system_check_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'rake_helper'
-describe SystemCheck, lib: true do
+describe SystemCheck do
class SimpleCheck < SystemCheck::BaseCheck
def check?
true
@@ -19,7 +19,7 @@ describe SystemCheck, lib: true do
end
describe '.run' do
- subject { SystemCheck }
+ subject { described_class }
it 'detects execution of SimpleCheck' do
is_expected.to execute_check(SimpleCheck)
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index 8c1c9bf135f..09e5094cf84 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -91,6 +91,36 @@ describe Emails::Profile do
end
end
+ describe 'user added gpg key' do
+ let(:gpg_key) { create(:gpg_key) }
+
+ subject { Notify.new_gpg_key_email(gpg_key.id) }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+
+ it 'is sent to the new user' do
+ is_expected.to deliver_to gpg_key.user.email
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject /^GPG key was added to your account$/i
+ end
+
+ it 'contains the new gpg key title' do
+ is_expected.to have_body_text /#{gpg_key.fingerprint}/
+ end
+
+ it 'includes a link to gpg keys page' do
+ is_expected.to have_body_text /#{profile_gpg_keys_path}/
+ end
+
+ context 'with GPG key that does not exist' do
+ it { expect { Notify.new_gpg_key_email('foo') }.not_to raise_error }
+ end
+ end
+
describe 'user added email' do
let(:email) { create(:email) }
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 980b24370d0..683e893968b 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -52,7 +52,7 @@ describe Notify do
it 'has the correct subject and body' do
aggregate_failures do
is_expected.to have_referable_subject(issue)
- is_expected.to have_body_text(namespace_project_issue_path(project.namespace, project, issue))
+ is_expected.to have_body_text(project_issue_path(project, issue))
end
end
@@ -99,7 +99,7 @@ describe Notify do
is_expected.to have_referable_subject(issue, reply: true)
is_expected.to have_html_escaped_body_text(previous_assignee.name)
is_expected.to have_html_escaped_body_text(assignee.name)
- is_expected.to have_body_text(namespace_project_issue_path(project.namespace, project, issue))
+ is_expected.to have_body_text(project_issue_path(project, issue))
end
end
end
@@ -125,7 +125,7 @@ describe Notify do
aggregate_failures do
is_expected.to have_referable_subject(issue, reply: true)
is_expected.to have_body_text('foo, bar, and baz')
- is_expected.to have_body_text(namespace_project_issue_path(project.namespace, project, issue))
+ is_expected.to have_body_text(project_issue_path(project, issue))
end
end
@@ -165,7 +165,7 @@ describe Notify do
is_expected.to have_referable_subject(issue, reply: true)
is_expected.to have_body_text(status)
is_expected.to have_html_escaped_body_text(current_user.name)
- is_expected.to have_body_text(namespace_project_issue_path project.namespace, project, issue)
+ is_expected.to have_body_text(project_issue_path project, issue)
end
end
end
@@ -185,13 +185,12 @@ describe Notify do
end
it 'has the correct subject and body' do
- new_issue_url = namespace_project_issue_path(new_issue.project.namespace,
- new_issue.project, new_issue)
+ new_issue_url = project_issue_path(new_issue.project, new_issue)
aggregate_failures do
is_expected.to have_referable_subject(issue, reply: true)
is_expected.to have_body_text(new_issue_url)
- is_expected.to have_body_text(namespace_project_issue_path(project.namespace, project, issue))
+ is_expected.to have_body_text(project_issue_path(project, issue))
end
end
end
@@ -216,7 +215,7 @@ describe Notify do
it 'has the correct subject and body' do
aggregate_failures do
is_expected.to have_referable_subject(merge_request)
- is_expected.to have_body_text(namespace_project_merge_request_path(project.namespace, project, merge_request))
+ is_expected.to have_body_text(project_merge_request_path(project, merge_request))
is_expected.to have_body_text(merge_request.source_branch)
is_expected.to have_body_text(merge_request.target_branch)
end
@@ -265,7 +264,7 @@ describe Notify do
aggregate_failures do
is_expected.to have_referable_subject(merge_request, reply: true)
is_expected.to have_html_escaped_body_text(previous_assignee.name)
- is_expected.to have_body_text(namespace_project_merge_request_path(project.namespace, project, merge_request))
+ is_expected.to have_body_text(project_merge_request_path(project, merge_request))
is_expected.to have_html_escaped_body_text(assignee.name)
end
end
@@ -291,7 +290,7 @@ describe Notify do
it 'has the correct subject and body' do
is_expected.to have_referable_subject(merge_request, reply: true)
is_expected.to have_body_text('foo, bar, and baz')
- is_expected.to have_body_text(namespace_project_merge_request_path(project.namespace, project, merge_request))
+ is_expected.to have_body_text(project_merge_request_path(project, merge_request))
end
end
@@ -316,7 +315,7 @@ describe Notify do
is_expected.to have_referable_subject(merge_request, reply: true)
is_expected.to have_body_text(status)
is_expected.to have_html_escaped_body_text(current_user.name)
- is_expected.to have_body_text(namespace_project_merge_request_path(project.namespace, project, merge_request))
+ is_expected.to have_body_text(project_merge_request_path(project, merge_request))
end
end
end
@@ -341,7 +340,7 @@ describe Notify do
aggregate_failures do
is_expected.to have_referable_subject(merge_request, reply: true)
is_expected.to have_body_text('merged')
- is_expected.to have_body_text(namespace_project_merge_request_path(project.namespace, project, merge_request))
+ is_expected.to have_body_text(project_merge_request_path(project, merge_request))
end
end
end
@@ -390,7 +389,7 @@ describe Notify do
is_expected.to have_subject "Request to join the #{project.name_with_namespace} project"
is_expected.to have_html_escaped_body_text project.name_with_namespace
- is_expected.to have_body_text namespace_project_project_members_url(project.namespace, project)
+ is_expected.to have_body_text project_project_members_url(project)
is_expected.to have_body_text project_member.human_access
end
end
@@ -417,7 +416,7 @@ describe Notify do
is_expected.to have_subject "Request to join the #{project.name_with_namespace} project"
is_expected.to have_html_escaped_body_text project.name_with_namespace
- is_expected.to have_body_text namespace_project_project_members_url(project.namespace, project)
+ is_expected.to have_body_text project_project_members_url(project)
is_expected.to have_body_text project_member.human_access
end
end
@@ -609,7 +608,7 @@ describe Notify do
describe 'on a merge request' do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
- let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") }
+ let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") }
before do
allow(note).to receive(:noteable).and_return(merge_request)
@@ -634,7 +633,7 @@ describe Notify do
describe 'on an issue' do
let(:issue) { create(:issue, project: project) }
- let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") }
+ let(:note_on_issue_path) { project_issue_path(project, issue, anchor: "note_#{note.id}") }
before do
allow(note).to receive(:noteable).and_return(issue)
@@ -725,7 +724,7 @@ describe Notify do
describe 'on a merge request' do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: note_author) }
- let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") }
+ let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") }
before do
allow(note).to receive(:noteable).and_return(merge_request)
@@ -752,7 +751,7 @@ describe Notify do
describe 'on an issue' do
let(:issue) { create(:issue, project: project) }
let(:note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: note_author) }
- let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") }
+ let(:note_on_issue_path) { project_issue_path(project, issue, anchor: "note_#{note.id}") }
before do
allow(note).to receive(:noteable).and_return(issue)
@@ -1022,7 +1021,7 @@ describe Notify do
describe 'email on push for a created branch' do
let(:example_site_path) { root_path }
let(:user) { create(:user) }
- let(:tree_path) { namespace_project_tree_path(project.namespace, project, "empty-branch") }
+ let(:tree_path) { project_tree_path(project, "empty-branch") }
subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/empty-branch', action: :create) }
@@ -1048,7 +1047,7 @@ describe Notify do
describe 'email on push for a created tag' do
let(:example_site_path) { root_path }
let(:user) { create(:user) }
- let(:tree_path) { namespace_project_tree_path(project.namespace, project, "v1.0") }
+ let(:tree_path) { project_tree_path(project, "v1.0") }
subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/tags/v1.0', action: :create) }
@@ -1122,7 +1121,7 @@ describe Notify do
let(:raw_compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_image_commit.id, sample_commit.id) }
let(:compare) { Compare.decorate(raw_compare, project) }
let(:commits) { compare.commits }
- let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: Commit.new(compare.base, project), to: Commit.new(compare.head, project)) }
+ let(:diff_path) { project_compare_path(project, from: Commit.new(compare.base, project), to: Commit.new(compare.head, project)) }
let(:send_from_committer_email) { false }
let(:diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: project.merge_base_commit(sample_image_commit.id, sample_commit.id).id, head_sha: sample_commit.id) }
@@ -1216,7 +1215,7 @@ describe Notify do
let(:raw_compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_commit.parent_id, sample_commit.id) }
let(:compare) { Compare.decorate(raw_compare, project) }
let(:commits) { compare.commits }
- let(:diff_path) { namespace_project_commit_path(project.namespace, project, commits.first) }
+ let(:diff_path) { project_commit_path(project, commits.first) }
let(:diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: project.merge_base_commit(sample_image_commit.id, sample_commit.id).id, head_sha: sample_commit.id) }
subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, diff_refs: diff_refs) }
diff --git a/spec/migrations/add_foreign_key_to_merge_requests_spec.rb b/spec/migrations/add_foreign_key_to_merge_requests_spec.rb
new file mode 100644
index 00000000000..d9ad9a585f0
--- /dev/null
+++ b/spec/migrations/add_foreign_key_to_merge_requests_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20170713104829_add_foreign_key_to_merge_requests.rb')
+
+describe AddForeignKeyToMergeRequests, :migration do
+ let(:projects) { table(:projects) }
+ let(:merge_requests) { table(:merge_requests) }
+ let(:pipelines) { table(:ci_pipelines) }
+
+ before do
+ projects.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce')
+ pipelines.create!(project_id: projects.first.id,
+ ref: 'some-branch',
+ sha: 'abc12345')
+
+ # merge request without a pipeline
+ create_merge_request(head_pipeline_id: nil)
+
+ # merge request with non-existent pipeline
+ create_merge_request(head_pipeline_id: 1234)
+
+ # merge reqeust with existing pipeline assigned
+ create_merge_request(head_pipeline_id: pipelines.first.id)
+ end
+
+ it 'correctly adds a foreign key to head_pipeline_id' do
+ migrate!
+
+ expect(merge_requests.first.head_pipeline_id).to be_nil
+ expect(merge_requests.second.head_pipeline_id).to be_nil
+ expect(merge_requests.third.head_pipeline_id).to eq pipelines.first.id
+ end
+
+ def create_merge_request(**opts)
+ merge_requests.create!(source_project_id: projects.first.id,
+ target_project_id: projects.first.id,
+ source_branch: 'some-branch',
+ target_branch: 'master', **opts)
+ end
+end
diff --git a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb
index bd5f85b901d..65bea662b02 100644
--- a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb
+++ b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20170508170547_add_head_pipeline_for_each_merge_request.rb')
-describe AddHeadPipelineForEachMergeRequest do
+describe AddHeadPipelineForEachMergeRequest, :truncate do
let(:migration) { described_class.new }
let!(:project) { create(:empty_project) }
diff --git a/spec/migrations/clean_appearance_symlinks_spec.rb b/spec/migrations/clean_appearance_symlinks_spec.rb
new file mode 100644
index 00000000000..9225dc0d894
--- /dev/null
+++ b/spec/migrations/clean_appearance_symlinks_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170613111224_clean_appearance_symlinks.rb')
+
+describe CleanAppearanceSymlinks do
+ let(:migration) { described_class.new }
+ let(:test_dir) { File.join(Rails.root, "tmp", "tests", "clean_appearance_test") }
+ let(:uploads_dir) { File.join(test_dir, "public", "uploads") }
+ let(:new_uploads_dir) { File.join(uploads_dir, "system") }
+ let(:original_path) { File.join(new_uploads_dir, 'appearance') }
+ let(:symlink_path) { File.join(uploads_dir, 'appearance') }
+
+ before do
+ FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
+ FileUtils.mkdir_p(uploads_dir)
+ allow(migration).to receive(:base_directory).and_return(test_dir)
+ allow(migration).to receive(:say)
+ end
+
+ describe "#up" do
+ before do
+ FileUtils.mkdir_p(original_path)
+ FileUtils.ln_s(original_path, symlink_path)
+ end
+
+ it 'removes the symlink' do
+ migration.up
+
+ expect(File.symlink?(symlink_path)).to be(false)
+ end
+ end
+
+ describe '#down' do
+ before do
+ FileUtils.mkdir_p(File.join(original_path))
+ FileUtils.touch(File.join(original_path, 'dummy.file'))
+ end
+
+ it 'creates a symlink' do
+ expected_path = File.join(symlink_path, "dummy.file")
+ migration.down
+
+ expect(File.exist?(expected_path)).to be(true)
+ expect(File.symlink?(symlink_path)).to be(true)
+ end
+ end
+end
diff --git a/spec/migrations/clean_stage_id_reference_migration_spec.rb b/spec/migrations/clean_stage_id_reference_migration_spec.rb
new file mode 100644
index 00000000000..9a581df28a2
--- /dev/null
+++ b/spec/migrations/clean_stage_id_reference_migration_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20170710083355_clean_stage_id_reference_migration.rb')
+
+describe CleanStageIdReferenceMigration, :migration, :sidekiq, :redis do
+ let(:migration_class) { 'MigrateBuildStageIdReference' }
+ let(:migration) { spy('migration') }
+
+ before do
+ allow(Gitlab::BackgroundMigration.const_get(migration_class))
+ .to receive(:new).and_return(migration)
+ end
+
+ context 'when there are pending background migrations' do
+ it 'processes pending jobs synchronously' do
+ Sidekiq::Testing.disable! do
+ BackgroundMigrationWorker.perform_in(2.minutes, migration_class, [1, 1])
+ BackgroundMigrationWorker.perform_async(migration_class, [1, 1])
+
+ migrate!
+
+ expect(migration).to have_received(:perform).with(1, 1).twice
+ end
+ end
+ end
+ context 'when there are no background migrations pending' do
+ it 'does nothing' do
+ Sidekiq::Testing.disable! do
+ migrate!
+
+ expect(migration).not_to have_received(:perform)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb b/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb
new file mode 100644
index 00000000000..3a9fa8c7113
--- /dev/null
+++ b/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+require Rails.root.join("db", "post_migrate", "20170717111152_cleanup_move_system_upload_folder_symlink.rb")
+
+describe CleanupMoveSystemUploadFolderSymlink do
+ let(:migration) { described_class.new }
+ let(:test_base) { File.join(Rails.root, 'tmp', 'tests', 'move-system-upload-folder') }
+ let(:test_folder) { File.join(test_base, '-', 'system') }
+
+ before do
+ allow(migration).to receive(:base_directory).and_return(test_base)
+ FileUtils.rm_rf(test_base)
+ FileUtils.mkdir_p(test_folder)
+ allow(migration).to receive(:say)
+ end
+
+ describe '#up' do
+ before do
+ FileUtils.ln_s(test_folder, File.join(test_base, 'system'))
+ end
+
+ it 'removes the symlink' do
+ migration.up
+
+ expect(File.exist?(File.join(test_base, 'system'))).to be_falsey
+ end
+ end
+
+ describe '#down' do
+ it 'creates the symlink' do
+ migration.down
+
+ expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy
+ end
+ end
+end
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
index 4223d2337a8..5b633dd349b 100644
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
@@ -54,7 +54,7 @@ describe MigrateProcessCommitWorkerJobs do
end
end
- describe '#up', :redis do
+ describe '#up', :clean_gitlab_redis_shared_state do
let(:migration) { described_class.new }
def job_count
@@ -172,7 +172,7 @@ describe MigrateProcessCommitWorkerJobs do
end
end
- describe '#down', :redis do
+ describe '#down', :clean_gitlab_redis_shared_state do
let(:migration) { described_class.new }
def job_count
diff --git a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
new file mode 100644
index 00000000000..260378adaa7
--- /dev/null
+++ b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170628080858_migrate_stage_id_reference_in_background')
+
+describe MigrateStageIdReferenceInBackground, :migration, :sidekiq do
+ matcher :be_scheduled_migration do |delay, *expected|
+ match do |migration|
+ BackgroundMigrationWorker.jobs.any? do |job|
+ job['args'] == [migration, expected] &&
+ job['at'].to_i == (delay.to_i + Time.now.to_i)
+ end
+ end
+
+ failure_message do |migration|
+ "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
+ end
+ end
+
+ let(:jobs) { table(:ci_builds) }
+ let(:stages) { table(:ci_stages) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:projects) { table(:projects) }
+
+ before do
+ stub_const("#{described_class.name}::BATCH_SIZE", 3)
+ stub_const("#{described_class.name}::RANGE_SIZE", 2)
+
+ projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
+ projects.create!(id: 345, name: 'gitlab2', path: 'gitlab2')
+
+ pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
+ pipelines.create!(id: 2, project_id: 345, ref: 'feature', sha: 'cdf43c3c')
+
+ jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
+ jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
+ jobs.create!(id: 3, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
+ jobs.create!(id: 4, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy')
+ jobs.create!(id: 5, commit_id: 2, project_id: 345, stage_idx: 1, stage: 'test')
+
+ stages.create(id: 101, pipeline_id: 1, project_id: 123, name: 'test')
+ stages.create(id: 102, pipeline_id: 1, project_id: 123, name: 'build')
+ stages.create(id: 103, pipeline_id: 1, project_id: 123, name: 'deploy')
+
+ jobs.create!(id: 6, commit_id: 2, project_id: 345, stage_id: 101, stage_idx: 1, stage: 'test')
+ end
+
+ it 'correctly schedules background migrations' do
+ Sidekiq::Testing.fake! do
+ Timecop.freeze do
+ migrate!
+
+ expect(described_class::MIGRATION).to be_scheduled_migration(2.minutes, 1, 2)
+ expect(described_class::MIGRATION).to be_scheduled_migration(2.minutes, 3, 3)
+ expect(described_class::MIGRATION).to be_scheduled_migration(4.minutes, 4, 5)
+ expect(BackgroundMigrationWorker.jobs.size).to eq 3
+ end
+ end
+ end
+
+ it 'schedules background migrations' do
+ Sidekiq::Testing.inline! do
+ expect(jobs.where(stage_id: nil).count).to eq 5
+
+ migrate!
+
+ expect(jobs.where(stage_id: nil).count).to eq 1
+ end
+ end
+end
diff --git a/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb b/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb
index 1db9bc002ae..063829be546 100644
--- a/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb
+++ b/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb
@@ -3,13 +3,13 @@
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20170324160416_migrate_user_activities_to_users_last_activity_on.rb')
-describe MigrateUserActivitiesToUsersLastActivityOn, :redis do
+describe MigrateUserActivitiesToUsersLastActivityOn, :clean_gitlab_redis_shared_state, :truncate do
let(:migration) { described_class.new }
let!(:user_active_1) { create(:user) }
let!(:user_active_2) { create(:user) }
def record_activity(user, time)
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::SharedState.with do |redis|
redis.zadd(described_class::USER_ACTIVITY_SET_KEY, time.to_i, user.username)
end
end
diff --git a/spec/migrations/migrate_user_project_view_spec.rb b/spec/migrations/migrate_user_project_view_spec.rb
index 70f8e0d6082..afaa5d836a7 100644
--- a/spec/migrations/migrate_user_project_view_spec.rb
+++ b/spec/migrations/migrate_user_project_view_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20170406142253_migrate_user_project_view.rb')
-describe MigrateUserProjectView do
+describe MigrateUserProjectView, :truncate do
let(:migration) { described_class.new }
let!(:user) { create(:user) }
diff --git a/spec/migrations/move_personal_snippets_files_spec.rb b/spec/migrations/move_personal_snippets_files_spec.rb
new file mode 100644
index 00000000000..8505c7bf3e3
--- /dev/null
+++ b/spec/migrations/move_personal_snippets_files_spec.rb
@@ -0,0 +1,180 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170612071012_move_personal_snippets_files.rb')
+
+describe MovePersonalSnippetsFiles do
+ let(:migration) { described_class.new }
+ let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_snippet_files_test") }
+ let(:uploads_dir) { File.join(test_dir, 'uploads') }
+ let(:new_uploads_dir) { File.join(uploads_dir, 'system') }
+
+ before do
+ allow(CarrierWave).to receive(:root).and_return(test_dir)
+ allow(migration).to receive(:base_directory).and_return(test_dir)
+ FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
+ allow(migration).to receive(:say)
+ end
+
+ describe "#up" do
+ let(:snippet) do
+ snippet = create(:personal_snippet)
+ create_upload('picture.jpg', snippet)
+ snippet.update(description: markdown_linking_file('picture.jpg', snippet))
+ snippet
+ end
+
+ let(:snippet_with_missing_file) do
+ snippet = create(:snippet)
+ create_upload('picture.jpg', snippet, create_file: false)
+ snippet.update(description: markdown_linking_file('picture.jpg', snippet))
+ snippet
+ end
+
+ it 'moves the files' do
+ source_path = File.join(uploads_dir, model_file_path('picture.jpg', snippet))
+ destination_path = File.join(new_uploads_dir, model_file_path('picture.jpg', snippet))
+
+ migration.up
+
+ expect(File.exist?(source_path)).to be_falsy
+ expect(File.exist?(destination_path)).to be_truthy
+ end
+
+ describe 'updating the markdown' do
+ it 'includes the new path when the file exists' do
+ secret = "secret#{snippet.id}"
+ file_location = "/uploads/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
+
+ migration.up
+
+ expect(snippet.reload.description).to include(file_location)
+ end
+
+ it 'does not update the markdown when the file is missing' do
+ secret = "secret#{snippet_with_missing_file.id}"
+ file_location = "/uploads/personal_snippet/#{snippet_with_missing_file.id}/#{secret}/picture.jpg"
+
+ migration.up
+
+ expect(snippet_with_missing_file.reload.description).to include(file_location)
+ end
+
+ it 'updates the note markdown' do
+ secret = "secret#{snippet.id}"
+ file_location = "/uploads/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
+ markdown = markdown_linking_file('picture.jpg', snippet)
+ note = create(:note_on_personal_snippet, noteable: snippet, note: "with #{markdown}")
+
+ migration.up
+
+ expect(note.reload.note).to include(file_location)
+ end
+ end
+ end
+
+ describe "#down" do
+ let(:snippet) do
+ snippet = create(:personal_snippet)
+ create_upload('picture.jpg', snippet, in_new_path: true)
+ snippet.update(description: markdown_linking_file('picture.jpg', snippet, in_new_path: true))
+ snippet
+ end
+
+ let(:snippet_with_missing_file) do
+ snippet = create(:personal_snippet)
+ create_upload('picture.jpg', snippet, create_file: false, in_new_path: true)
+ snippet.update(description: markdown_linking_file('picture.jpg', snippet, in_new_path: true))
+ snippet
+ end
+
+ it 'moves the files' do
+ source_path = File.join(new_uploads_dir, model_file_path('picture.jpg', snippet))
+ destination_path = File.join(uploads_dir, model_file_path('picture.jpg', snippet))
+
+ migration.down
+
+ expect(File.exist?(source_path)).to be_falsey
+ expect(File.exist?(destination_path)).to be_truthy
+ end
+
+ describe 'updating the markdown' do
+ it 'includes the new path when the file exists' do
+ secret = "secret#{snippet.id}"
+ file_location = "/uploads/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
+
+ migration.down
+
+ expect(snippet.reload.description).to include(file_location)
+ end
+
+ it 'keeps the markdown as is when the file is missing' do
+ secret = "secret#{snippet_with_missing_file.id}"
+ file_location = "/uploads/system/personal_snippet/#{snippet_with_missing_file.id}/#{secret}/picture.jpg"
+
+ migration.down
+
+ expect(snippet_with_missing_file.reload.description).to include(file_location)
+ end
+
+ it 'updates the note markdown' do
+ markdown = markdown_linking_file('picture.jpg', snippet, in_new_path: true)
+ secret = "secret#{snippet.id}"
+ file_location = "/uploads/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
+ note = create(:note_on_personal_snippet, noteable: snippet, note: "with #{markdown}")
+
+ migration.down
+
+ expect(note.reload.note).to include(file_location)
+ end
+ end
+ end
+
+ describe '#update_markdown' do
+ it 'escapes sql in the snippet description' do
+ migration.instance_variable_set('@source_relative_location', '/uploads/personal_snippet')
+ migration.instance_variable_set('@destination_relative_location', '/uploads/system/personal_snippet')
+
+ secret = '123456789'
+ filename = 'hello.jpg'
+ snippet = create(:personal_snippet)
+
+ path_before = "/uploads/personal_snippet/#{snippet.id}/#{secret}/#{filename}"
+ path_after = "/uploads/system/personal_snippet/#{snippet.id}/#{secret}/#{filename}"
+ description_before = "Hello world; ![image](#{path_before})'; select * from users;"
+ description_after = "Hello world; ![image](#{path_after})'; select * from users;"
+
+ migration.update_markdown(snippet.id, secret, filename, description_before)
+
+ expect(snippet.reload.description).to eq(description_after)
+ end
+ end
+
+ def create_upload(filename, snippet, create_file: true, in_new_path: false)
+ secret = "secret#{snippet.id}"
+ absolute_path = if in_new_path
+ File.join(new_uploads_dir, model_file_path(filename, snippet))
+ else
+ File.join(uploads_dir, model_file_path(filename, snippet))
+ end
+
+ if create_file
+ FileUtils.mkdir_p(File.dirname(absolute_path))
+ FileUtils.touch(absolute_path)
+ end
+
+ create(:upload, model: snippet, path: "#{secret}/#{filename}", uploader: PersonalFileUploader)
+ end
+
+ def markdown_linking_file(filename, snippet, in_new_path: false)
+ markdown = "![#{filename.split('.')[0]}]"
+ markdown += '(/uploads'
+ markdown += '/system' if in_new_path
+ markdown += "/#{model_file_path(filename, snippet)})"
+ markdown
+ end
+
+ def model_file_path(filename, snippet)
+ secret = "secret#{snippet.id}"
+
+ File.join('personal_snippet', snippet.id.to_s, secret, filename)
+ end
+end
diff --git a/spec/migrations/move_system_upload_folder_spec.rb b/spec/migrations/move_system_upload_folder_spec.rb
new file mode 100644
index 00000000000..b622b4e9536
--- /dev/null
+++ b/spec/migrations/move_system_upload_folder_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+require Rails.root.join("db", "migrate", "20170717074009_move_system_upload_folder.rb")
+
+describe MoveSystemUploadFolder do
+ let(:migration) { described_class.new }
+ let(:test_base) { File.join(Rails.root, 'tmp', 'tests', 'move-system-upload-folder') }
+
+ before do
+ allow(migration).to receive(:base_directory).and_return(test_base)
+ FileUtils.rm_rf(test_base)
+ FileUtils.mkdir_p(test_base)
+ allow(migration).to receive(:say)
+ end
+
+ describe '#up' do
+ let(:test_folder) { File.join(test_base, 'system') }
+ let(:test_file) { File.join(test_folder, 'file') }
+
+ before do
+ FileUtils.mkdir_p(test_folder)
+ FileUtils.touch(test_file)
+ end
+
+ it 'moves the related folder' do
+ migration.up
+
+ expect(File.exist?(File.join(test_base, '-', 'system', 'file'))).to be_truthy
+ end
+
+ it 'creates a symlink linking making the new folder available on the old path' do
+ migration.up
+
+ expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy
+ expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy
+ end
+ end
+
+ describe '#down' do
+ let(:test_folder) { File.join(test_base, '-', 'system') }
+ let(:test_file) { File.join(test_folder, 'file') }
+
+ before do
+ FileUtils.mkdir_p(test_folder)
+ FileUtils.touch(test_file)
+ end
+
+ it 'moves the system folder back to the old location' do
+ migration.down
+
+ expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy
+ end
+
+ it 'removes the symlink if it existed' do
+ FileUtils.ln_s(test_folder, File.join(test_base, 'system'))
+
+ migration.down
+
+ expect(File.directory?(File.join(test_base, 'system'))).to be_truthy
+ expect(File.symlink?(File.join(test_base, 'system'))).to be_falsey
+ end
+ end
+end
diff --git a/spec/migrations/rename_duplicated_variable_key_spec.rb b/spec/migrations/rename_duplicated_variable_key_spec.rb
new file mode 100644
index 00000000000..11096564dfa
--- /dev/null
+++ b/spec/migrations/rename_duplicated_variable_key_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20170622135451_rename_duplicated_variable_key.rb')
+
+describe RenameDuplicatedVariableKey, :migration do
+ let(:variables) { table(:ci_variables) }
+ let(:projects) { table(:projects) }
+
+ before do
+ projects.create!(id: 1)
+ variables.create!(id: 1, key: 'key1', project_id: 1)
+ variables.create!(id: 2, key: 'key2', project_id: 1)
+ variables.create!(id: 3, key: 'keyX', project_id: 1)
+ variables.create!(id: 4, key: 'keyX', project_id: 1)
+ variables.create!(id: 5, key: 'keyY', project_id: 1)
+ variables.create!(id: 6, key: 'keyX', project_id: 1)
+ variables.create!(id: 7, key: 'key7', project_id: 1)
+ variables.create!(id: 8, key: 'keyY', project_id: 1)
+ end
+
+ it 'correctly remove duplicated records with smaller id' do
+ migrate!
+
+ expect(variables.pluck(:id, :key)).to contain_exactly(
+ [1, 'key1'],
+ [2, 'key2'],
+ [3, 'keyX_3'],
+ [4, 'keyX_4'],
+ [5, 'keyY_5'],
+ [6, 'keyX'],
+ [7, 'key7'],
+ [8, 'keyY']
+ )
+ end
+end
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb
index 090f9e70c50..aa019288700 100644
--- a/spec/models/ability_spec.rb
+++ b/spec/models/ability_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Ability, lib: true do
+describe Ability do
context 'using a nil subject' do
- it 'is always empty' do
- expect(Ability.allowed(nil, nil).to_set).to be_empty
+ it 'has no permissions' do
+ expect(described_class.policy_for(nil, nil)).to be_banned
end
end
@@ -98,7 +98,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
- expect(project).to receive(:owner).twice.and_return(user1)
+ expect(project).to receive(:owner).at_least(:once).and_return(user1)
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@@ -109,7 +109,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
- expect(project.team).to receive(:members).twice.and_return([user1])
+ expect(project.team).to receive(:members).at_least(:once).and_return([user1])
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@@ -140,7 +140,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
- expect(project).to receive(:owner).twice.and_return(user1)
+ expect(project).to receive(:owner).at_least(:once).and_return(user1)
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@@ -151,7 +151,7 @@ describe Ability, lib: true do
user2 = build(:user, external: true)
users = [user1, user2]
- expect(project.team).to receive(:members).twice.and_return([user1])
+ expect(project.team).to receive(:members).at_least(:once).and_return([user1])
expect(described_class.users_that_can_read_project(users, project))
.to eq([user1])
@@ -255,12 +255,15 @@ describe Ability, lib: true do
describe '.project_disabled_features_rules' do
let(:project) { create(:empty_project, :wiki_disabled) }
- subject { described_class.allowed(project.owner, project) }
+ subject { described_class.policy_for(project.owner, project) }
context 'wiki named abilities' do
it 'disables wiki abilities if the project has no wiki' do
expect(project).to receive(:has_external_wiki?).and_return(false)
- expect(subject).not_to include(:read_wiki, :create_wiki, :update_wiki, :admin_wiki)
+ expect(subject).not_to be_allowed(:read_wiki)
+ expect(subject).not_to be_allowed(:create_wiki)
+ expect(subject).not_to be_allowed(:update_wiki)
+ expect(subject).not_to be_allowed(:admin_wiki)
end
end
end
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index c1bf5551fe0..d4da30b1641 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-RSpec.describe AbuseReport, type: :model do
+RSpec.describe AbuseReport do
subject { create(:abuse_report) }
let(:user) { create(:admin) }
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
index 1060bf3cbf4..7cd3a84d592 100644
--- a/spec/models/appearance_spec.rb
+++ b/spec/models/appearance_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-RSpec.describe Appearance, type: :model do
+RSpec.describe Appearance do
subject { build(:appearance) }
it { is_expected.to be_valid }
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 166a4474abf..359753b600e 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe ApplicationSetting, models: true do
- let(:setting) { ApplicationSetting.create_from_defaults }
+describe ApplicationSetting do
+ let(:setting) { described_class.create_from_defaults }
it { expect(setting).to be_valid }
it { expect(setting.uuid).to be_present }
@@ -155,6 +155,18 @@ describe ApplicationSetting, models: true do
end
end
+ describe '.current' do
+ context 'redis unavailable' do
+ it 'returns an ApplicationSetting' do
+ allow(Rails.cache).to receive(:fetch).and_call_original
+ allow(described_class).to receive(:last).and_return(:last)
+ expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(ArgumentError)
+
+ expect(described_class.current).to eq(:last)
+ end
+ end
+ end
+
context 'restricted signup domains' do
it 'sets single domain' do
setting.domain_whitelist_raw = 'example.com'
@@ -214,6 +226,160 @@ describe ApplicationSetting, models: true do
end
end
+ describe 'performance bar settings' do
+ describe 'performance_bar_allowed_group_id=' do
+ context 'with a blank path' do
+ before do
+ setting.performance_bar_allowed_group_id = create(:group).full_path
+ end
+
+ it 'persists nil for a "" path and clears allowed user IDs cache' do
+ expect(Gitlab::PerformanceBar).to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_allowed_group_id = ''
+
+ expect(setting.performance_bar_allowed_group_id).to be_nil
+ end
+ end
+
+ context 'with an invalid path' do
+ it 'does not persist an invalid group path' do
+ setting.performance_bar_allowed_group_id = 'foo'
+
+ expect(setting.performance_bar_allowed_group_id).to be_nil
+ end
+ end
+
+ context 'with a path to an existing group' do
+ let(:group) { create(:group) }
+
+ it 'persists a valid group path and clears allowed user IDs cache' do
+ expect(Gitlab::PerformanceBar).to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_allowed_group_id = group.full_path
+
+ expect(setting.performance_bar_allowed_group_id).to eq(group.id)
+ end
+
+ context 'when the given path is the same' do
+ context 'with a blank path' do
+ before do
+ setting.performance_bar_allowed_group_id = nil
+ end
+
+ it 'clears the cached allowed user IDs' do
+ expect(Gitlab::PerformanceBar).not_to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_allowed_group_id = ''
+ end
+ end
+
+ context 'with a valid path' do
+ before do
+ setting.performance_bar_allowed_group_id = group.full_path
+ end
+
+ it 'clears the cached allowed user IDs' do
+ expect(Gitlab::PerformanceBar).not_to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_allowed_group_id = group.full_path
+ end
+ end
+ end
+ end
+ end
+
+ describe 'performance_bar_allowed_group' do
+ context 'with no performance_bar_allowed_group_id saved' do
+ it 'returns nil' do
+ expect(setting.performance_bar_allowed_group).to be_nil
+ end
+ end
+
+ context 'with a performance_bar_allowed_group_id saved' do
+ let(:group) { create(:group) }
+
+ before do
+ setting.performance_bar_allowed_group_id = group.full_path
+ end
+
+ it 'returns the group' do
+ expect(setting.performance_bar_allowed_group).to eq(group)
+ end
+ end
+ end
+
+ describe 'performance_bar_enabled' do
+ context 'with the Performance Bar is enabled' do
+ let(:group) { create(:group) }
+
+ before do
+ setting.performance_bar_allowed_group_id = group.full_path
+ end
+
+ it 'returns true' do
+ expect(setting.performance_bar_enabled).to be_truthy
+ end
+ end
+ end
+
+ describe 'performance_bar_enabled=' do
+ context 'when the performance bar is enabled' do
+ let(:group) { create(:group) }
+
+ before do
+ setting.performance_bar_allowed_group_id = group.full_path
+ end
+
+ context 'when passing true' do
+ it 'does not clear allowed user IDs cache' do
+ expect(Gitlab::PerformanceBar).not_to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_enabled = true
+
+ expect(setting.performance_bar_allowed_group_id).to eq(group.id)
+ expect(setting.performance_bar_enabled).to be_truthy
+ end
+ end
+
+ context 'when passing false' do
+ it 'disables the performance bar and clears allowed user IDs cache' do
+ expect(Gitlab::PerformanceBar).to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_enabled = false
+
+ expect(setting.performance_bar_allowed_group_id).to be_nil
+ expect(setting.performance_bar_enabled).to be_falsey
+ end
+ end
+ end
+
+ context 'when the performance bar is disabled' do
+ context 'when passing true' do
+ it 'does nothing and does not clear allowed user IDs cache' do
+ expect(Gitlab::PerformanceBar).not_to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_enabled = true
+
+ expect(setting.performance_bar_allowed_group_id).to be_nil
+ expect(setting.performance_bar_enabled).to be_falsey
+ end
+ end
+
+ context 'when passing false' do
+ it 'does nothing and does not clear allowed user IDs cache' do
+ expect(Gitlab::PerformanceBar).not_to receive(:expire_allowed_user_ids_cache)
+
+ setting.performance_bar_enabled = false
+
+ expect(setting.performance_bar_allowed_group_id).to be_nil
+ expect(setting.performance_bar_enabled).to be_falsey
+ end
+ end
+ end
+ end
+ end
+
describe 'usage ping settings' do
context 'when the usage ping is disabled in gitlab.yml' do
before do
diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb
index 2a9a27752c1..87e60d9c16b 100644
--- a/spec/models/award_emoji_spec.rb
+++ b/spec/models/award_emoji_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe AwardEmoji, models: true do
+describe AwardEmoji do
describe 'Associations' do
it { is_expected.to belong_to(:awardable) }
it { is_expected.to belong_to(:user) }
diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb
index 574438838d8..e3640097dff 100644
--- a/spec/models/blob_viewer/base_spec.rb
+++ b/spec/models/blob_viewer/base_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::Base, model: true do
+describe BlobViewer::Base do
include FakeBlobHelpers
let(:project) { build(:empty_project) }
diff --git a/spec/models/blob_viewer/changelog_spec.rb b/spec/models/blob_viewer/changelog_spec.rb
index 9066c5a05ac..db41eca0fc8 100644
--- a/spec/models/blob_viewer/changelog_spec.rb
+++ b/spec/models/blob_viewer/changelog_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::Changelog, model: true do
+describe BlobViewer::Changelog do
include FakeBlobHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/models/blob_viewer/composer_json_spec.rb b/spec/models/blob_viewer/composer_json_spec.rb
index df4f1f4815c..82f6f7e5046 100644
--- a/spec/models/blob_viewer/composer_json_spec.rb
+++ b/spec/models/blob_viewer/composer_json_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::ComposerJson, model: true do
+describe BlobViewer::ComposerJson do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/gemspec_spec.rb b/spec/models/blob_viewer/gemspec_spec.rb
index 81e932de290..14cc5f3c0fd 100644
--- a/spec/models/blob_viewer/gemspec_spec.rb
+++ b/spec/models/blob_viewer/gemspec_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::Gemspec, model: true do
+describe BlobViewer::Gemspec do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
index 0c6c24ece21..7a4f9866375 100644
--- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
+++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::GitlabCiYml, model: true do
+describe BlobViewer::GitlabCiYml do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/license_spec.rb b/spec/models/blob_viewer/license_spec.rb
index 944ddd32b92..222ed166ee0 100644
--- a/spec/models/blob_viewer/license_spec.rb
+++ b/spec/models/blob_viewer/license_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::License, model: true do
+describe BlobViewer::License do
include FakeBlobHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb
index 5c9a9c81963..96fb1b08c99 100644
--- a/spec/models/blob_viewer/package_json_spec.rb
+++ b/spec/models/blob_viewer/package_json_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::PackageJson, model: true do
+describe BlobViewer::PackageJson do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/podspec_json_spec.rb b/spec/models/blob_viewer/podspec_json_spec.rb
index 42a00940bc5..f510077a87b 100644
--- a/spec/models/blob_viewer/podspec_json_spec.rb
+++ b/spec/models/blob_viewer/podspec_json_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::PodspecJson, model: true do
+describe BlobViewer::PodspecJson do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/podspec_spec.rb b/spec/models/blob_viewer/podspec_spec.rb
index 6c9f0f42d53..7c38083550c 100644
--- a/spec/models/blob_viewer/podspec_spec.rb
+++ b/spec/models/blob_viewer/podspec_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::Podspec, model: true do
+describe BlobViewer::Podspec do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/readme_spec.rb b/spec/models/blob_viewer/readme_spec.rb
new file mode 100644
index 00000000000..926df21ffda
--- /dev/null
+++ b/spec/models/blob_viewer/readme_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe BlobViewer::Readme do
+ include FakeBlobHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:blob) { fake_blob(path: 'README.md') }
+ subject { described_class.new(blob) }
+
+ describe '#render_error' do
+ context 'when there is no wiki' do
+ it 'returns :no_wiki' do
+ expect(subject.render_error).to eq(:no_wiki)
+ end
+ end
+
+ context 'when there is an external wiki' do
+ before do
+ project.has_external_wiki = true
+ end
+
+ it 'returns nil' do
+ expect(subject.render_error).to be_nil
+ end
+ end
+
+ context 'when there is a local wiki' do
+ before do
+ project.wiki_enabled = true
+ end
+
+ context 'when the wiki is empty' do
+ it 'returns :no_wiki' do
+ expect(subject.render_error).to eq(:no_wiki)
+ end
+ end
+
+ context 'when the wiki is not empty' do
+ before do
+ WikiPages::CreateService.new(project, project.owner, title: 'home', content: 'Home page').execute
+ end
+
+ it 'returns nil' do
+ expect(subject.render_error).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/blob_viewer/route_map_spec.rb b/spec/models/blob_viewer/route_map_spec.rb
index 4854e0262d9..115731b4970 100644
--- a/spec/models/blob_viewer/route_map_spec.rb
+++ b/spec/models/blob_viewer/route_map_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::RouteMap, model: true do
+describe BlobViewer::RouteMap do
include FakeBlobHelpers
let(:project) { build(:project) }
diff --git a/spec/models/blob_viewer/server_side_spec.rb b/spec/models/blob_viewer/server_side_spec.rb
index f047953d540..2639eec9e84 100644
--- a/spec/models/blob_viewer/server_side_spec.rb
+++ b/spec/models/blob_viewer/server_side_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BlobViewer::ServerSide, model: true do
+describe BlobViewer::ServerSide do
include FakeBlobHelpers
let(:project) { build(:empty_project) }
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 333f4139a96..a8ca1d110e4 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BroadcastMessage, models: true do
+describe BroadcastMessage do
subject { build(:broadcast_message) }
it { is_expected.to be_valid }
@@ -24,26 +24,26 @@ describe BroadcastMessage, models: true do
it 'returns message if time match' do
message = create(:broadcast_message)
- expect(BroadcastMessage.current).to include(message)
+ expect(described_class.current).to include(message)
end
it 'returns multiple messages if time match' do
message1 = create(:broadcast_message)
message2 = create(:broadcast_message)
- expect(BroadcastMessage.current).to contain_exactly(message1, message2)
+ expect(described_class.current).to contain_exactly(message1, message2)
end
it 'returns empty list if time not come' do
create(:broadcast_message, :future)
- expect(BroadcastMessage.current).to be_empty
+ expect(described_class.current).to be_empty
end
it 'returns empty list if time has passed' do
create(:broadcast_message, :expired)
- expect(BroadcastMessage.current).to be_empty
+ expect(described_class.current).to be_empty
end
end
diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb
index b02971cab82..8581bcbb08b 100644
--- a/spec/models/chat_name_spec.rb
+++ b/spec/models/chat_name_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatName, models: true do
+describe ChatName do
subject { create(:chat_name) }
it { is_expected.to belong_to(:service) }
diff --git a/spec/models/chat_team_spec.rb b/spec/models/chat_team_spec.rb
index 5283561a83f..e0e5f73e6fe 100644
--- a/spec/models/chat_team_spec.rb
+++ b/spec/models/chat_team_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatTeam, type: :model do
+describe ChatTeam do
subject { create(:chat_team) }
# Associations
diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb
index 968593d7e9b..a10a8af5303 100644
--- a/spec/models/ci/artifact_blob_spec.rb
+++ b/spec/models/ci/artifact_blob_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::ArtifactBlob, models: true do
+describe Ci::ArtifactBlob do
let(:build) { create(:ci_build, :artifacts) }
let(:entry) { build.artifacts_metadata_entry('other_artifacts_0.1.2/another-subdirectory/banana_sample.gif') }
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 488697f74eb..86afa856ea7 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Build, :models do
+describe Ci::Build do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) }
@@ -225,7 +225,7 @@ describe Ci::Build, :models do
it 'expects to have retried builds instead the original ones' do
project.add_developer(user)
- retried_rspec = Ci::Build.retry(rspec_test, user)
+ retried_rspec = described_class.retry(rspec_test, user)
expect(staging.depends_on_builds.map(&:id))
.to contain_exactly(build.id, retried_rspec.id, rubocop_test.id)
@@ -620,9 +620,9 @@ describe Ci::Build, :models do
describe '#first_pending' do
let!(:first) { create(:ci_build, pipeline: pipeline, status: 'pending', created_at: Date.yesterday) }
let!(:second) { create(:ci_build, pipeline: pipeline, status: 'pending') }
- subject { Ci::Build.first_pending }
+ subject { described_class.first_pending }
- it { is_expected.to be_a(Ci::Build) }
+ it { is_expected.to be_a(described_class) }
it('returns with the first pending build') { is_expected.to eq(first) }
end
@@ -802,6 +802,47 @@ describe Ci::Build, :models do
end
end
+ describe 'build auto retry feature' do
+ describe '#retries_count' do
+ subject { create(:ci_build, name: 'test', pipeline: pipeline) }
+
+ context 'when build has been retried several times' do
+ before do
+ create(:ci_build, :retried, name: 'test', pipeline: pipeline)
+ create(:ci_build, :retried, name: 'test', pipeline: pipeline)
+ end
+
+ it 'reports a correct retry count value' do
+ expect(subject.retries_count).to eq 2
+ end
+ end
+
+ context 'when build has not been retried' do
+ it 'returns zero' do
+ expect(subject.retries_count).to eq 0
+ end
+ end
+ end
+
+ describe '#retries_max' do
+ context 'when max retries value is defined' do
+ subject { create(:ci_build, options: { retry: 1 }) }
+
+ it 'returns a number of configured max retries' do
+ expect(subject.retries_max).to eq 1
+ end
+ end
+
+ context 'when max retries value is not defined' do
+ subject { create(:ci_build) }
+
+ it 'returns zero' do
+ expect(subject.retries_max).to eq 0
+ end
+ end
+ end
+ end
+
describe '#keep_artifacts!' do
let(:build) { create(:ci_build, artifacts_expire_at: Time.now + 7.days) }
@@ -863,7 +904,7 @@ describe Ci::Build, :models do
pipeline2 = create(:ci_pipeline, project: project)
@build2 = create(:ci_build, pipeline: pipeline2)
- allow(@merge_request).to receive(:commits_sha)
+ allow(@merge_request).to receive(:commit_shas)
.and_return([pipeline.sha, pipeline2.sha])
allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request])
end
@@ -904,7 +945,7 @@ describe Ci::Build, :models do
end
context 'when build is retried' do
- let!(:new_build) { Ci::Build.retry(build, user) }
+ let!(:new_build) { described_class.retry(build, user) }
it 'does not return any of them' do
is_expected.not_to include(build, new_build)
@@ -912,7 +953,7 @@ describe Ci::Build, :models do
end
context 'when other build is retried' do
- let!(:retried_build) { Ci::Build.retry(other_build, user) }
+ let!(:retried_build) { described_class.retry(other_build, user) }
before do
retried_build.success
@@ -998,13 +1039,17 @@ describe Ci::Build, :models do
describe '#ref_slug' do
{
- 'master' => 'master',
- '1-foo' => '1-foo',
- 'fix/1-foo' => 'fix-1-foo',
- 'fix-1-foo' => 'fix-1-foo',
- 'a' * 63 => 'a' * 63,
- 'a' * 64 => 'a' * 63,
- 'FOO' => 'foo'
+ 'master' => 'master',
+ '1-foo' => '1-foo',
+ 'fix/1-foo' => 'fix-1-foo',
+ 'fix-1-foo' => 'fix-1-foo',
+ 'a' * 63 => 'a' * 63,
+ 'a' * 64 => 'a' * 63,
+ 'FOO' => 'foo',
+ '-' + 'a' * 61 + '-' => 'a' * 61,
+ '-' + 'a' * 62 + '-' => 'a' * 62,
+ '-' + 'a' * 63 + '-' => 'a' * 62,
+ 'a' * 62 + ' ' => 'a' * 62
}.each do |ref, slug|
it "transforms #{ref} to #{slug}" do
build.ref = ref
@@ -1179,6 +1224,7 @@ describe Ci::Build, :models do
{ key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true },
{ key: 'CI_PROJECT_URL', value: project.web_url, public: true },
{ key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true },
+ { key: 'CI_CONFIG_PATH', value: pipeline.ci_yaml_file_path, public: true },
{ key: 'CI_REGISTRY_USER', value: 'gitlab-ci-token', public: true },
{ key: 'CI_REGISTRY_PASSWORD', value: build.token, public: false },
{ key: 'CI_REPOSITORY_URL', value: build.repo_url, public: false }
@@ -1351,6 +1397,59 @@ describe Ci::Build, :models do
end
end
+ context 'when group secret variable is defined' do
+ let(:secret_variable) do
+ { key: 'SECRET_KEY', value: 'secret_value', public: false }
+ end
+
+ let(:group) { create(:group, :access_requestable) }
+
+ before do
+ build.project.update(group: group)
+
+ create(:ci_group_variable,
+ secret_variable.slice(:key, :value).merge(group: group))
+ end
+
+ it { is_expected.to include(secret_variable) }
+ end
+
+ context 'when group protected variable is defined' do
+ let(:protected_variable) do
+ { key: 'PROTECTED_KEY', value: 'protected_value', public: false }
+ end
+
+ let(:group) { create(:group, :access_requestable) }
+
+ before do
+ build.project.update(group: group)
+
+ create(:ci_group_variable,
+ :protected,
+ protected_variable.slice(:key, :value).merge(group: group))
+ end
+
+ context 'when the branch is protected' do
+ before do
+ create(:protected_branch, project: build.project, name: build.ref)
+ end
+
+ it { is_expected.to include(protected_variable) }
+ end
+
+ context 'when the tag is protected' do
+ before do
+ create(:protected_tag, project: build.project, name: build.ref)
+ end
+
+ it { is_expected.to include(protected_variable) }
+ end
+
+ context 'when the ref is not protected' do
+ it { is_expected.not_to include(protected_variable) }
+ end
+ end
+
context 'when build is for triggers' do
let(:trigger) { create(:ci_trigger, project: project) }
let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) }
@@ -1369,6 +1468,29 @@ describe Ci::Build, :models do
it { is_expected.to include(predefined_trigger_variable) }
end
+ context 'when pipeline has a variable' do
+ let!(:pipeline_variable) { create(:ci_pipeline_variable, pipeline: pipeline) }
+
+ it { is_expected.to include(pipeline_variable.to_runner_variable) }
+ end
+
+ context 'when a job was triggered by a pipeline schedule' do
+ let(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) }
+
+ let!(:pipeline_schedule_variable) do
+ create(:ci_pipeline_schedule_variable,
+ key: 'SCHEDULE_VARIABLE_KEY',
+ pipeline_schedule: pipeline_schedule)
+ end
+
+ before do
+ pipeline_schedule.pipelines << pipeline
+ pipeline_schedule.reload
+ end
+
+ it { is_expected.to include(pipeline_schedule_variable.to_runner_variable) }
+ end
+
context 'when yaml_variables are undefined' do
before do
build.yaml_variables = nil
@@ -1469,6 +1591,16 @@ describe Ci::Build, :models do
it { is_expected.to include(deployment_variable) }
end
+ context 'when project has custom CI config path' do
+ let(:ci_config_path) { { key: 'CI_CONFIG_PATH', value: 'custom', public: true } }
+
+ before do
+ project.update(ci_config_path: 'custom')
+ end
+
+ it { is_expected.to include(ci_config_path) }
+ end
+
context 'returns variables in valid order' do
let(:build_pre_var) { { key: 'build', value: 'value' } }
let(:project_pre_var) { { key: 'project', value: 'value' } }
@@ -1481,9 +1613,10 @@ describe Ci::Build, :models do
allow(pipeline).to receive(:predefined_variables) { [pipeline_pre_var] }
allow(build).to receive(:yaml_variables) { [build_yaml_var] }
- allow(project).to receive(:secret_variables_for).with(build.ref) do
- [create(:ci_variable, key: 'secret', value: 'value')]
- end
+ allow(project).to receive(:secret_variables_for)
+ .with(ref: 'master', environment: nil) do
+ [create(:ci_variable, key: 'secret', value: 'value')]
+ end
end
it do
@@ -1497,7 +1630,7 @@ describe Ci::Build, :models do
end
end
- describe 'State transition: any => [:pending]' do
+ describe 'state transition: any => [:pending]' do
let(:build) { create(:ci_build, :created) }
it 'queues BuildQueueWorker' do
@@ -1506,4 +1639,35 @@ describe Ci::Build, :models do
build.enqueue
end
end
+
+ describe 'state transition when build fails' do
+ context 'when build is configured to be retried' do
+ subject { create(:ci_build, :running, options: { retry: 3 }) }
+
+ it 'retries builds and assigns a same user to it' do
+ expect(described_class).to receive(:retry)
+ .with(subject, subject.user)
+
+ subject.drop!
+ end
+ end
+
+ context 'when build is not configured to be retried' do
+ subject { create(:ci_build, :running) }
+
+ it 'does not retry build' do
+ expect(described_class).not_to receive(:retry)
+
+ subject.drop!
+ end
+
+ it 'does not count retries when not necessary' do
+ expect(described_class).not_to receive(:retry)
+ expect_any_instance_of(described_class)
+ .not_to receive(:retries_count)
+
+ subject.drop!
+ end
+ end
+ end
end
diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb
index 62e15093089..51123e73fe6 100644
--- a/spec/models/ci/group_spec.rb
+++ b/spec/models/ci/group_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Group, models: true do
+describe Ci::Group do
subject do
described_class.new('test', name: 'rspec', jobs: jobs)
end
diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb
new file mode 100644
index 00000000000..145189e7469
--- /dev/null
+++ b/spec/models/ci/group_variable_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Ci::GroupVariable do
+ subject { build(:ci_group_variable) }
+
+ it { is_expected.to include_module(HasVariable) }
+ it { is_expected.to include_module(Presentable) }
+ it { is_expected.to validate_uniqueness_of(:key).scoped_to(:group_id) }
+
+ describe '.unprotected' do
+ subject { described_class.unprotected }
+
+ context 'when variable is protected' do
+ before do
+ create(:ci_group_variable, :protected)
+ end
+
+ it 'returns nothing' do
+ is_expected.to be_empty
+ end
+ end
+
+ context 'when variable is not protected' do
+ let(:variable) { create(:ci_group_variable, protected: false) }
+
+ it 'returns the variable' do
+ is_expected.to contain_exactly(variable)
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb
index d43c33d3807..0c33c1466b7 100644
--- a/spec/models/ci/legacy_stage_spec.rb
+++ b/spec/models/ci/legacy_stage_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::LegacyStage, :models do
+describe Ci::LegacyStage do
let(:stage) { build(:ci_stage) }
let(:pipeline) { stage.pipeline }
let(:stage_name) { stage.name }
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index 56817baf79d..9a278212efc 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -1,10 +1,11 @@
require 'spec_helper'
-describe Ci::PipelineSchedule, models: true do
+describe Ci::PipelineSchedule do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:owner) }
it { is_expected.to have_many(:pipelines) }
+ it { is_expected.to have_many(:variables) }
it { is_expected.to respond_to(:ref) }
it { is_expected.to respond_to(:cron) }
@@ -45,7 +46,7 @@ describe Ci::PipelineSchedule, models: true do
end
it 'updates next_run_at automatically' do
- expect(Ci::PipelineSchedule.last.next_run_at).to eq(expected_next_run_at)
+ expect(described_class.last.next_run_at).to eq(expected_next_run_at)
end
end
@@ -60,7 +61,7 @@ describe Ci::PipelineSchedule, models: true do
it 'updates next_run_at automatically' do
pipeline_schedule.update!(cron: new_cron)
- expect(Ci::PipelineSchedule.last.next_run_at).to eq(expected_next_run_at)
+ expect(described_class.last.next_run_at).to eq(expected_next_run_at)
end
end
end
@@ -117,4 +118,20 @@ describe Ci::PipelineSchedule, models: true do
end
end
end
+
+ describe '#job_variables' do
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule) }
+
+ let!(:pipeline_schedule_variables) do
+ create_list(:ci_pipeline_schedule_variable, 2, pipeline_schedule: pipeline_schedule)
+ end
+
+ subject { pipeline_schedule.job_variables }
+
+ before do
+ pipeline_schedule.reload
+ end
+
+ it { is_expected.to contain_exactly(*pipeline_schedule_variables.map(&:to_runner_variable)) }
+ end
end
diff --git a/spec/models/ci/pipeline_schedule_variable_spec.rb b/spec/models/ci/pipeline_schedule_variable_spec.rb
new file mode 100644
index 00000000000..dc8427f28bc
--- /dev/null
+++ b/spec/models/ci/pipeline_schedule_variable_spec.rb
@@ -0,0 +1,7 @@
+require 'spec_helper'
+
+describe Ci::PipelineScheduleVariable do
+ subject { build(:ci_pipeline_schedule_variable) }
+
+ it { is_expected.to include_module(HasVariable) }
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index dab8e8ca432..b0efa689a07 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Pipeline, models: true do
+describe Ci::Pipeline do
include EmailHelpers
let(:user) { create(:user) }
@@ -17,6 +17,7 @@ describe Ci::Pipeline, models: true do
it { is_expected.to have_many(:statuses) }
it { is_expected.to have_many(:trigger_requests) }
+ it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:builds) }
it { is_expected.to have_many(:auto_canceled_pipelines) }
it { is_expected.to have_many(:auto_canceled_jobs) }
@@ -672,6 +673,12 @@ describe Ci::Pipeline, models: true do
end
end
+ describe '.internal_sources' do
+ subject { described_class.internal_sources }
+
+ it { is_expected.to be_an(Array) }
+ end
+
describe '#status' do
let(:build) do
create(:ci_build, :created, pipeline: pipeline, name: 'test')
@@ -728,6 +735,8 @@ describe Ci::Pipeline, models: true do
context 'on failure and build retry' do
before do
+ stub_not_protect_default_branch
+
build.drop
project.add_developer(user)
@@ -742,6 +751,39 @@ describe Ci::Pipeline, models: true do
end
end
+ describe '#ci_yaml_file_path' do
+ subject { pipeline.ci_yaml_file_path }
+
+ it 'returns the path from project' do
+ allow(pipeline.project).to receive(:ci_config_path) { 'custom/path' }
+
+ is_expected.to eq('custom/path')
+ end
+
+ it 'returns default when custom path is nil' do
+ allow(pipeline.project).to receive(:ci_config_path) { nil }
+
+ is_expected.to eq('.gitlab-ci.yml')
+ end
+
+ it 'returns default when custom path is empty' do
+ allow(pipeline.project).to receive(:ci_config_path) { '' }
+
+ is_expected.to eq('.gitlab-ci.yml')
+ end
+ end
+
+ describe '#ci_yaml_file' do
+ it 'reports error if the file is not found' do
+ allow(pipeline.project).to receive(:ci_config_path) { 'custom' }
+
+ pipeline.ci_yaml_file
+
+ expect(pipeline.yaml_errors)
+ .to eq('Failed to load CI/CD config file at custom')
+ end
+ end
+
describe '#detailed_status' do
subject { pipeline.detailed_status(user) }
@@ -960,6 +1002,8 @@ describe Ci::Pipeline, models: true do
let(:latest_status) { pipeline.statuses.latest.pluck(:status) }
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
diff --git a/spec/models/ci/pipeline_variable_spec.rb b/spec/models/ci/pipeline_variable_spec.rb
new file mode 100644
index 00000000000..2ce78e34b0c
--- /dev/null
+++ b/spec/models/ci/pipeline_variable_spec.rb
@@ -0,0 +1,8 @@
+require 'spec_helper'
+
+describe Ci::PipelineVariable, models: true do
+ subject { build(:ci_pipeline_variable) }
+
+ it { is_expected.to include_module(HasVariable) }
+ it { is_expected.to validate_uniqueness_of(:key).scoped_to(:pipeline_id) }
+end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 76ce558eea0..8d12a9c09ca 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Runner, models: true do
+describe Ci::Runner do
describe 'validation' do
context 'when runner is not allowed to pick untagged jobs' do
context 'when runner does not have tags' do
@@ -50,7 +50,7 @@ describe Ci::Runner, models: true do
end
describe '.online' do
- subject { Ci::Runner.online }
+ subject { described_class.online }
before do
@runner1 = FactoryGirl.create(:ci_runner, :shared, contacted_at: 1.year.ago)
@@ -276,14 +276,14 @@ describe Ci::Runner, models: true do
it 'sets a new last_update value when it is called the first time' do
last_update = runner.ensure_runner_queue_value
- expect_value_in_redis.to eq(last_update)
+ expect_value_in_queues.to eq(last_update)
end
it 'does not change if it is not expired and called again' do
last_update = runner.ensure_runner_queue_value
expect(runner.ensure_runner_queue_value).to eq(last_update)
- expect_value_in_redis.to eq(last_update)
+ expect_value_in_queues.to eq(last_update)
end
context 'updates runner queue after changing editable value' do
@@ -294,7 +294,7 @@ describe Ci::Runner, models: true do
end
it 'sets a new last_update value' do
- expect_value_in_redis.not_to eq(last_update)
+ expect_value_in_queues.not_to eq(last_update)
end
end
@@ -306,12 +306,12 @@ describe Ci::Runner, models: true do
end
it 'has an old last_update value' do
- expect_value_in_redis.to eq(last_update)
+ expect_value_in_queues.to eq(last_update)
end
end
- def expect_value_in_redis
- Gitlab::Redis.with do |redis|
+ def expect_value_in_queues
+ Gitlab::Redis::Queues.with do |redis|
runner_queue_key = runner.send(:runner_queue_key)
expect(redis.get(runner_queue_key))
end
@@ -330,7 +330,7 @@ describe Ci::Runner, models: true do
end
it 'cleans up the queue' do
- Gitlab::Redis.with do |redis|
+ Gitlab::Redis::Queues.with do |redis|
expect(redis.get(queue_key)).to be_nil
end
end
@@ -352,13 +352,13 @@ describe Ci::Runner, models: true do
end
context 'does not give owned runner' do
- subject { Ci::Runner.assignable_for(project) }
+ subject { described_class.assignable_for(project) }
it { is_expected.to be_empty }
end
context 'does not give shared runner' do
- subject { Ci::Runner.assignable_for(another_project) }
+ subject { described_class.assignable_for(another_project) }
it { is_expected.to be_empty }
end
@@ -366,13 +366,13 @@ describe Ci::Runner, models: true do
context 'with unlocked runner' do
context 'does not give owned runner' do
- subject { Ci::Runner.assignable_for(project) }
+ subject { described_class.assignable_for(project) }
it { is_expected.to be_empty }
end
context 'does give a specific runner' do
- subject { Ci::Runner.assignable_for(another_project) }
+ subject { described_class.assignable_for(another_project) }
it { is_expected.to contain_exactly(runner) }
end
@@ -384,13 +384,13 @@ describe Ci::Runner, models: true do
end
context 'does not give owned runner' do
- subject { Ci::Runner.assignable_for(project) }
+ subject { described_class.assignable_for(project) }
it { is_expected.to be_empty }
end
context 'does not give a locked runner' do
- subject { Ci::Runner.assignable_for(another_project) }
+ subject { described_class.assignable_for(another_project) }
it { is_expected.to be_empty }
end
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index 92c15c13c18..de51f4879fd 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Trigger, models: true do
+describe Ci::Trigger do
let(:project) { create :empty_project }
describe 'associations' do
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index 83494af24ba..e4ff551151e 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -1,16 +1,13 @@
require 'spec_helper'
-describe Ci::Variable, models: true do
+describe Ci::Variable do
subject { build(:ci_variable) }
- let(:secret_value) { 'secret' }
-
- it { is_expected.to validate_presence_of(:key) }
- it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id) }
- it { is_expected.to validate_length_of(:key).is_at_most(255) }
- it { is_expected.to allow_value('foo').for(:key) }
- it { is_expected.not_to allow_value('foo bar').for(:key) }
- it { is_expected.not_to allow_value('foo/bar').for(:key) }
+ describe 'validations' do
+ it { is_expected.to include_module(HasVariable) }
+ it { is_expected.to include_module(Presentable) }
+ it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope) }
+ end
describe '.unprotected' do
subject { described_class.unprotected }
@@ -33,36 +30,4 @@ describe Ci::Variable, models: true do
end
end
end
-
- describe '#value' do
- before do
- subject.value = secret_value
- end
-
- it 'stores the encrypted value' do
- expect(subject.encrypted_value).not_to be_nil
- end
-
- it 'stores an iv for value' do
- expect(subject.encrypted_value_iv).not_to be_nil
- end
-
- it 'stores a salt for value' do
- expect(subject.encrypted_value_salt).not_to be_nil
- end
-
- it 'fails to decrypt if iv is incorrect' do
- subject.encrypted_value_iv = SecureRandom.hex
- subject.instance_variable_set(:@value, nil)
- expect { subject.value }
- .to raise_error(OpenSSL::Cipher::CipherError, 'bad decrypt')
- end
- end
-
- describe '#to_runner_variable' do
- it 'returns a hash for the runner' do
- expect(subject.to_runner_variable)
- .to eq(key: subject.key, value: subject.value, public: false)
- end
- end
end
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index ba9c3f66d21..07e10b44938 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CommitRange, models: true do
+describe CommitRange do
describe 'modules' do
subject { described_class }
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 6056d78da4e..2285c338599 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Commit, models: true do
+describe Commit do
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
@@ -19,17 +19,15 @@ describe Commit, models: true do
expect(commit.author).to eq(user)
end
- it 'caches the author' do
- allow(RequestStore).to receive(:active?).and_return(true)
+ it 'caches the author', :request_store do
user = create(:user, email: commit.author_email)
- expect_any_instance_of(Commit).to receive(:find_author_by_any_email).and_call_original
+ expect(User).to receive(:find_by_any_email).and_call_original
expect(commit.author).to eq(user)
- key = "commit_author:#{commit.author_email}"
+ key = "Commit:author:#{commit.author_email.downcase}"
expect(RequestStore.store[key]).to eq(user)
expect(commit.author).to eq(user)
- RequestStore.store.clear
end
end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 9262ce08987..6fb4794ea5f 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CommitStatus, :models do
+describe CommitStatus do
let(:project) { create(:project, :repository) }
let(:pipeline) do
@@ -284,6 +284,41 @@ describe CommitStatus, :models do
end
end
+ describe '.status' do
+ context 'when there are multiple statuses present' do
+ before do
+ create_status(status: 'running')
+ create_status(status: 'success')
+ create_status(allow_failure: true, status: 'failed')
+ end
+
+ it 'returns a correct compound status' do
+ expect(described_class.all.status).to eq 'running'
+ end
+ end
+
+ context 'when there are only allowed to fail commit statuses present' do
+ before do
+ create_status(allow_failure: true, status: 'failed')
+ end
+
+ it 'returns status that indicates success' do
+ expect(described_class.all.status).to eq 'success'
+ end
+ end
+
+ context 'when using a scope to select latest statuses' do
+ before do
+ create_status(name: 'test', retried: true, status: 'failed')
+ create_status(allow_failure: true, name: 'test', status: 'failed')
+ end
+
+ it 'returns status according to the scope' do
+ expect(described_class.latest.status).to eq 'success'
+ end
+ end
+ end
+
describe '#before_sha' do
subject { commit_status.before_sha }
diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb
index da003dbf794..04f3cecae00 100644
--- a/spec/models/compare_spec.rb
+++ b/spec/models/compare_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Compare, models: true do
+describe Compare do
include RepoHelpers
let(:project) { create(:project, :public, :repository) }
diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb
index a6fccb668e3..5c0dfaeb4d3 100644
--- a/spec/models/concerns/case_sensitivity_spec.rb
+++ b/spec/models/concerns/case_sensitivity_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CaseSensitivity, models: true do
+describe CaseSensitivity do
describe '.iwhere' do
let(:connection) { ActiveRecord::Base.connection }
let(:model) { Class.new { include CaseSensitivity } }
diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb
index f3e148f95f0..2322eb206fb 100644
--- a/spec/models/concerns/discussion_on_diff_spec.rb
+++ b/spec/models/concerns/discussion_on_diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DiscussionOnDiff, model: true do
+describe DiscussionOnDiff do
subject { create(:diff_note_on_merge_request).to_discussion }
describe "#truncated_diff_lines" do
diff --git a/spec/models/concerns/each_batch_spec.rb b/spec/models/concerns/each_batch_spec.rb
new file mode 100644
index 00000000000..951690a217b
--- /dev/null
+++ b/spec/models/concerns/each_batch_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe EachBatch do
+ describe '.each_batch' do
+ let(:model) do
+ Class.new(ActiveRecord::Base) do
+ include EachBatch
+
+ self.table_name = 'users'
+ end
+ end
+
+ before do
+ 5.times { create(:user, updated_at: 1.day.ago) }
+ end
+
+ it 'yields an ActiveRecord::Relation when a block is given' do
+ model.each_batch do |relation|
+ expect(relation).to be_a_kind_of(ActiveRecord::Relation)
+ end
+ end
+
+ it 'yields a batch index as the second argument' do
+ model.each_batch do |_, index|
+ expect(index).to eq(1)
+ end
+ end
+
+ it 'accepts a custom batch size' do
+ amount = 0
+
+ model.each_batch(of: 1) { amount += 1 }
+
+ expect(amount).to eq(5)
+ end
+
+ it 'does not include ORDER BYs in the yielded relations' do
+ model.each_batch do |relation|
+ expect(relation.to_sql).not_to include('ORDER BY')
+ end
+ end
+
+ it 'allows updating of the yielded relations' do
+ time = Time.now
+
+ model.each_batch do |relation|
+ relation.update_all(updated_at: time)
+ end
+
+ expect(model.where(updated_at: time).count).to eq(5)
+ end
+ end
+end
diff --git a/spec/models/concerns/feature_gate_spec.rb b/spec/models/concerns/feature_gate_spec.rb
new file mode 100644
index 00000000000..3f601243245
--- /dev/null
+++ b/spec/models/concerns/feature_gate_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe FeatureGate do
+ describe 'User' do
+ describe '#flipper_id' do
+ context 'when user is not persisted' do
+ let(:user) { build(:user) }
+
+ it { expect(user.flipper_id).to be_nil }
+ end
+
+ context 'when user is persisted' do
+ let(:user) { create(:user) }
+
+ it { expect(user.flipper_id).to eq "User:#{user.id}" }
+ end
+ end
+ end
+end
diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb
index 101567998c9..a38f2553eb1 100644
--- a/spec/models/concerns/has_status_spec.rb
+++ b/spec/models/concerns/has_status_spec.rb
@@ -48,7 +48,7 @@ describe HasStatus do
[create(type, status: :failed, allow_failure: true)]
end
- it { is_expected.to eq 'skipped' }
+ it { is_expected.to eq 'success' }
end
context 'success and canceled' do
diff --git a/spec/models/concerns/has_variable_spec.rb b/spec/models/concerns/has_variable_spec.rb
new file mode 100644
index 00000000000..f4b24e6d1d9
--- /dev/null
+++ b/spec/models/concerns/has_variable_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe HasVariable do
+ subject { build(:ci_variable) }
+
+ it { is_expected.to validate_presence_of(:key) }
+ it { is_expected.to validate_length_of(:key).is_at_most(255) }
+ it { is_expected.to allow_value('foo').for(:key) }
+ it { is_expected.not_to allow_value('foo bar').for(:key) }
+ it { is_expected.not_to allow_value('foo/bar').for(:key) }
+
+ describe '#value' do
+ before do
+ subject.value = 'secret'
+ end
+
+ it 'stores the encrypted value' do
+ expect(subject.encrypted_value).not_to be_nil
+ end
+
+ it 'stores an iv for value' do
+ expect(subject.encrypted_value_iv).not_to be_nil
+ end
+
+ it 'stores a salt for value' do
+ expect(subject.encrypted_value_salt).not_to be_nil
+ end
+
+ it 'fails to decrypt if iv is incorrect' do
+ subject.encrypted_value_iv = SecureRandom.hex
+ subject.instance_variable_set(:@value, nil)
+ expect { subject.value }
+ .to raise_error(OpenSSL::Cipher::CipherError, 'bad decrypt')
+ end
+ end
+
+ describe '#to_runner_variable' do
+ it 'returns a hash for the runner' do
+ expect(subject.to_runner_variable)
+ .to eq(key: subject.key, value: subject.value, public: false)
+ end
+ end
+end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index ac9303370ab..505039c9d88 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -155,7 +155,7 @@ describe Issuable do
end
describe "#sort" do
- let(:project) { build_stubbed(:empty_project) }
+ let(:project) { create(:empty_project) }
context "by milestone due date" do
# Correct order is:
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index e2a29e0ae70..1ad811736af 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -174,25 +174,25 @@ describe Commit, 'Mentionable' do
it "is false when message doesn't reference anything" do
allow(commit.raw).to receive(:message).and_return "WIP: Do something"
- expect(commit.matches_cross_reference_regex?).to be false
+ expect(commit.matches_cross_reference_regex?).to be_falsey
end
it 'is true if issue #number mentioned in title' do
allow(commit.raw).to receive(:message).and_return "#1"
- expect(commit.matches_cross_reference_regex?).to be true
+ expect(commit.matches_cross_reference_regex?).to be_truthy
end
it 'is true if references an MR' do
allow(commit.raw).to receive(:message).and_return "See merge request !12"
- expect(commit.matches_cross_reference_regex?).to be true
+ expect(commit.matches_cross_reference_regex?).to be_truthy
end
it 'is true if references a commit' do
allow(commit.raw).to receive(:message).and_return "a1b2c3d4"
- expect(commit.matches_cross_reference_regex?).to be true
+ expect(commit.matches_cross_reference_regex?).to be_truthy
end
it 'is true if issue referenced by url' do
@@ -200,7 +200,7 @@ describe Commit, 'Mentionable' do
allow(commit.raw).to receive(:message).and_return Gitlab::UrlBuilder.build(issue)
- expect(commit.matches_cross_reference_regex?).to be true
+ expect(commit.matches_cross_reference_regex?).to be_truthy
end
context 'with external issue tracker' do
@@ -209,7 +209,13 @@ describe Commit, 'Mentionable' do
it 'is true if external issues referenced' do
allow(commit.raw).to receive(:message).and_return 'JIRA-123'
- expect(commit.matches_cross_reference_regex?).to be true
+ expect(commit.matches_cross_reference_regex?).to be_truthy
+ end
+
+ it 'is true if internal issues referenced' do
+ allow(commit.raw).to receive(:message).and_return '#123'
+
+ expect(commit.matches_cross_reference_regex?).to be_truthy
end
end
end
diff --git a/spec/models/concerns/noteable_spec.rb b/spec/models/concerns/noteable_spec.rb
index bdae742ff1d..485a6e165a1 100644
--- a/spec/models/concerns/noteable_spec.rb
+++ b/spec/models/concerns/noteable_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Noteable, model: true do
+describe Noteable do
let!(:active_diff_note1) { create(:diff_note_on_merge_request) }
let(:project) { active_diff_note1.project }
subject { active_diff_note1.noteable }
diff --git a/spec/models/concerns/participable_spec.rb b/spec/models/concerns/participable_spec.rb
index a9f4ef9ee5e..431f1482615 100644
--- a/spec/models/concerns/participable_spec.rb
+++ b/spec/models/concerns/participable_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Participable, models: true do
+describe Participable do
let(:model) do
Class.new do
include Participable
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index 808247ebfd5..5f9b7e0a367 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ReactiveCaching, caching: true do
+describe ReactiveCaching, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers
class CacheTest
diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb
index 3934992c143..1616c2ea985 100644
--- a/spec/models/concerns/resolvable_discussion_spec.rb
+++ b/spec/models/concerns/resolvable_discussion_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Discussion, ResolvableDiscussion, models: true do
+describe Discussion, ResolvableDiscussion do
subject { described_class.new([first_note, second_note, third_note]) }
let(:first_note) { create(:discussion_note_on_merge_request) }
diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb
index 1503ccdff11..53eaa6f8461 100644
--- a/spec/models/concerns/resolvable_note_spec.rb
+++ b/spec/models/concerns/resolvable_note_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Note, ResolvableNote, models: true do
+describe Note, ResolvableNote do
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
subject { create(:discussion_note_on_merge_request, noteable: merge_request, project: project) }
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 65f05121b40..36aedd2f701 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -132,6 +132,19 @@ describe Group, 'Routable' do
end
end
+ describe '#expires_full_path_cache' do
+ context 'with RequestStore active', :request_store do
+ it 'expires the full_path cache' do
+ expect(group.full_path).to eq('foo')
+
+ group.route.update(path: 'bar', name: 'bar')
+ group.expires_full_path_cache
+
+ expect(group.full_path).to eq('bar')
+ end
+ end
+ end
+
describe '#full_name' do
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
diff --git a/spec/models/concerns/sha_attribute_spec.rb b/spec/models/concerns/sha_attribute_spec.rb
new file mode 100644
index 00000000000..21893e0cbaa
--- /dev/null
+++ b/spec/models/concerns/sha_attribute_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe ShaAttribute do
+ let(:model) { Class.new { include ShaAttribute } }
+
+ before do
+ columns = [
+ double(:column, name: 'name', type: :text),
+ double(:column, name: 'sha1', type: :binary)
+ ]
+
+ allow(model).to receive(:columns).and_return(columns)
+ end
+
+ describe '#sha_attribute' do
+ context 'when the table exists' do
+ before do
+ allow(model).to receive(:table_exists?).and_return(true)
+ end
+
+ it 'defines a SHA attribute for a binary column' do
+ expect(model).to receive(:attribute)
+ .with(:sha1, an_instance_of(Gitlab::Database::ShaAttribute))
+
+ model.sha_attribute(:sha1)
+ end
+
+ it 'raises ArgumentError when the column type is not :binary' do
+ expect { model.sha_attribute(:name) }.to raise_error(ArgumentError)
+ end
+ end
+
+ context 'when the table does not exist' do
+ before do
+ allow(model).to receive(:table_exists?).and_return(false)
+ end
+
+ it 'does nothing' do
+ expect(model).not_to receive(:columns)
+ expect(model).not_to receive(:attribute)
+
+ model.sha_attribute(:name)
+ end
+ end
+ end
+end
diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/models/concerns/uniquify_spec.rb
index 83187d732e4..914730718e7 100644
--- a/spec/models/concerns/uniquify_spec.rb
+++ b/spec/models/concerns/uniquify_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Uniquify, models: true do
+describe Uniquify do
let(:uniquify) { described_class.new }
describe "#string" do
diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb
index 9053485939e..f2f1928926c 100644
--- a/spec/models/cycle_analytics/code_spec.rb
+++ b/spec/models/cycle_analytics/code_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#code', feature: true do
+describe 'CycleAnalytics#code' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb
index fc7d18bd40e..985e1bf80be 100644
--- a/spec/models/cycle_analytics/issue_spec.rb
+++ b/spec/models/cycle_analytics/issue_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#issue', models: true do
+describe 'CycleAnalytics#issue' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb
index 4f33f3c6d69..6fbb2a2d102 100644
--- a/spec/models/cycle_analytics/plan_spec.rb
+++ b/spec/models/cycle_analytics/plan_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#plan', feature: true do
+describe 'CycleAnalytics#plan' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb
index 4744b9e05ea..f8681c0a2f9 100644
--- a/spec/models/cycle_analytics/production_spec.rb
+++ b/spec/models/cycle_analytics/production_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#production', feature: true do
+describe 'CycleAnalytics#production' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb
index febb18c9884..0ac58695b35 100644
--- a/spec/models/cycle_analytics/review_spec.rb
+++ b/spec/models/cycle_analytics/review_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#review', feature: true do
+describe 'CycleAnalytics#review' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb
index f78d7a23105..b66d5623910 100644
--- a/spec/models/cycle_analytics/staging_spec.rb
+++ b/spec/models/cycle_analytics/staging_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#staging', feature: true do
+describe 'CycleAnalytics#staging' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb
index fd58bd1d6ad..690c09bc2dc 100644
--- a/spec/models/cycle_analytics/test_spec.rb
+++ b/spec/models/cycle_analytics/test_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'CycleAnalytics#test', feature: true do
+describe 'CycleAnalytics#test' do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project, :repository) }
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index 8ef8218cf74..2aece75b817 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DeployKey, models: true do
+describe DeployKey do
include EmailHelpers
describe "Associations" do
diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb
index aacc178a19e..f10b65ba9d8 100644
--- a/spec/models/deploy_keys_project_spec.rb
+++ b/spec/models/deploy_keys_project_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DeployKeysProject, models: true do
+describe DeployKeysProject do
describe "Associations" do
it { is_expected.to belong_to(:deploy_key) }
it { is_expected.to belong_to(:project) }
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index aad215d5f41..6447095078b 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Deployment, models: true do
+describe Deployment do
subject { build(:deployment) }
it { is_expected.to belong_to(:project) }
@@ -30,7 +30,7 @@ describe Deployment, models: true do
end
describe '#includes_commit?' do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) }
let(:deployment) do
create(:deployment, environment: environment, sha: project.commit.id)
@@ -90,6 +90,36 @@ describe Deployment, models: true do
end
end
+ describe '#additional_metrics' do
+ let(:project) { create(:project) }
+ let(:deployment) { create(:deployment, project: project) }
+
+ subject { deployment.additional_metrics }
+
+ context 'metrics are disabled' do
+ it { is_expected.to eq({}) }
+ end
+
+ context 'metrics are enabled' do
+ let(:simple_metrics) do
+ {
+ success: true,
+ metrics: {},
+ last_update: 42
+ }
+ end
+
+ let(:prometheus_service) { double('prometheus_service') }
+
+ before do
+ allow(project).to receive(:prometheus_service).and_return(prometheus_service)
+ allow(prometheus_service).to receive(:additional_deployment_metrics).and_return(simple_metrics)
+ end
+
+ it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
+ end
+ end
+
describe '#stop_action' do
let(:build) { create(:ci_build) }
diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb
index 45b2f6e4beb..2704698f6c9 100644
--- a/spec/models/diff_discussion_spec.rb
+++ b/spec/models/diff_discussion_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DiffDiscussion, model: true do
+describe DiffDiscussion do
include RepoHelpers
subject { described_class.new([diff_note]) }
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 297c2108dc2..4aa9ec789a3 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DiffNote, models: true do
+describe DiffNote do
include RepoHelpers
let(:merge_request) { create(:merge_request) }
diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb
index 3755f4a56f3..b26de3f3b97 100644
--- a/spec/models/diff_viewer/base_spec.rb
+++ b/spec/models/diff_viewer/base_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DiffViewer::Base, model: true do
+describe DiffViewer::Base do
include FakeBlobHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb
index 2d926e06936..92e613f92de 100644
--- a/spec/models/diff_viewer/server_side_spec.rb
+++ b/spec/models/diff_viewer/server_side_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DiffViewer::ServerSide, model: true do
+describe DiffViewer::ServerSide do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
diff --git a/spec/models/discussion_spec.rb b/spec/models/discussion_spec.rb
index 0221e23ced8..a46f7ed6507 100644
--- a/spec/models/discussion_spec.rb
+++ b/spec/models/discussion_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Discussion, model: true do
+describe Discussion do
subject { described_class.new([first_note, second_note, third_note]) }
let(:first_note) { create(:diff_note_on_merge_request) }
diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb
index fe4de1b2afb..1d6fabe48b1 100644
--- a/spec/models/email_spec.rb
+++ b/spec/models/email_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Email, models: true do
+describe Email do
describe 'validations' do
it_behaves_like 'an object with email-formated attributes', :email do
subject { build(:email) }
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index f8123cb518e..ebf2c070116 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Environment, models: true do
+describe Environment do
set(:project) { create(:empty_project) }
subject(:environment) { create(:environment, project: project) }
@@ -120,28 +120,17 @@ describe Environment, models: true do
let(:head_commit) { project.commit }
let(:commit) { project.commit.parent }
- context 'Gitaly find_ref_name feature disabled' do
- it 'returns deployment id for the environment' do
- expect(environment.first_deployment_for(commit)).to eq deployment1
- end
+ it 'returns deployment id for the environment' do
+ expect(environment.first_deployment_for(commit)).to eq deployment1
+ end
- it 'return nil when no deployment is found' do
- expect(environment.first_deployment_for(head_commit)).to eq nil
- end
+ it 'return nil when no deployment is found' do
+ expect(environment.first_deployment_for(head_commit)).to eq nil
end
- # TODO: Uncomment when feature is reenabled
- # context 'Gitaly find_ref_name feature enabled' do
- # before do
- # allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:find_ref_name).and_return(true)
- # end
- #
- # it 'calls GitalyClient' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:find_ref_name)
- #
- # environment.first_deployment_for(commit)
- # end
- # end
+ it 'returns a UTF-8 ref' do
+ expect(environment.first_deployment_for(commit).ref).to be_utf8
+ end
end
describe '#environment_type' do
@@ -432,6 +421,99 @@ describe Environment, models: true do
end
end
+ describe '#has_metrics?' do
+ subject { environment.has_metrics? }
+
+ context 'when the enviroment is available' do
+ context 'with a deployment service' do
+ let(:project) { create(:prometheus_project) }
+
+ context 'and a deployment' do
+ let!(:deployment) { create(:deployment, environment: environment) }
+ it { is_expected.to be_truthy }
+ end
+
+ context 'but no deployments' do
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ context 'without a monitoring service' do
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ context 'when the environment is unavailable' do
+ let(:project) { create(:prometheus_project) }
+
+ before do
+ environment.stop
+ end
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ describe '#additional_metrics' do
+ let(:project) { create(:prometheus_project) }
+ subject { environment.additional_metrics }
+
+ context 'when the environment has additional metrics' do
+ before do
+ allow(environment).to receive(:has_additional_metrics?).and_return(true)
+ end
+
+ it 'returns the additional metrics from the deployment service' do
+ expect(project.prometheus_service).to receive(:additional_environment_metrics)
+ .with(environment)
+ .and_return(:fake_metrics)
+
+ is_expected.to eq(:fake_metrics)
+ end
+ end
+
+ context 'when the environment does not have metrics' do
+ before do
+ allow(environment).to receive(:has_additional_metrics?).and_return(false)
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#has_additional_metrics??' do
+ subject { environment.has_additional_metrics? }
+
+ context 'when the enviroment is available' do
+ context 'with a deployment service' do
+ let(:project) { create(:prometheus_project) }
+
+ context 'and a deployment' do
+ let!(:deployment) { create(:deployment, environment: environment) }
+ it { is_expected.to be_truthy }
+ end
+
+ context 'but no deployments' do
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ context 'without a monitoring service' do
+ it { is_expected.to be_falsy }
+ end
+ end
+
+ context 'when the environment is unavailable' do
+ let(:project) { create(:prometheus_project) }
+
+ before do
+ environment.stop
+ end
+
+ it { is_expected.to be_falsy }
+ end
+ end
+
describe '#slug' do
it "is automatically generated" do
expect(environment.slug).not_to be_nil
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 10b9bf9f43a..4a4b84c9566 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Event, models: true do
+describe Event do
describe "Associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:target) }
diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb
index cd50bda8996..c8748daf46b 100644
--- a/spec/models/external_issue_spec.rb
+++ b/spec/models/external_issue_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ExternalIssue, models: true do
+describe ExternalIssue do
let(:project) { double('project', id: 1, to_reference: 'namespace1/project1') }
let(:issue) { described_class.new('EXT-1234', project) }
diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb
index 6e8d43f988c..38fbdd2536a 100644
--- a/spec/models/forked_project_link_spec.rb
+++ b/spec/models/forked_project_link_spec.rb
@@ -2,53 +2,75 @@ require 'spec_helper'
describe ForkedProjectLink, "add link on fork" do
let(:project_from) { create(:project, :repository) }
+ let(:project_to) { fork_project(project_from, user) }
let(:user) { create(:user) }
let(:namespace) { user.namespace }
before do
- create(:project_member, :reporter, user: user, project: project_from)
- @project_to = fork_project(project_from, user)
+ project_from.add_reporter(user)
+ end
+
+ it 'project_from knows its forks' do
+ _ = project_to
+
+ expect(project_from.forks.count).to eq(1)
end
it "project_to knows it is forked" do
- expect(@project_to.forked?).to be_truthy
+ expect(project_to.forked?).to be_truthy
end
it "project knows who it is forked from" do
- expect(@project_to.forked_from_project).to eq(project_from)
+ expect(project_to.forked_from_project).to eq(project_from)
end
-end
-describe '#forked?' do
- let(:forked_project_link) { build(:forked_project_link) }
- let(:project_from) { create(:project, :repository) }
- let(:project_to) { create(:project, forked_project_link: forked_project_link) }
+ context 'project_to is pending_delete' do
+ before do
+ project_to.update!(pending_delete: true)
+ end
- before :each do
- forked_project_link.forked_from_project = project_from
- forked_project_link.forked_to_project = project_to
- forked_project_link.save!
+ it { expect(project_from.forks.count).to eq(0) }
end
- it "project_to knows it is forked" do
- expect(project_to.forked?).to be_truthy
- end
+ context 'project_from is pending_delete' do
+ before do
+ project_from.update!(pending_delete: true)
+ end
- it "project_from is not forked" do
- expect(project_from.forked?).to be_falsey
+ it { expect(project_to.forked_from_project).to be_nil }
end
- it "project_to.destroy destroys fork_link" do
- expect(forked_project_link).to receive(:destroy)
- project_to.destroy
+ describe '#forked?' do
+ let(:project_to) { create(:project, forked_project_link: forked_project_link) }
+ let(:forked_project_link) { create(:forked_project_link) }
+
+ before do
+ forked_project_link.forked_from_project = project_from
+ forked_project_link.forked_to_project = project_to
+ forked_project_link.save!
+ end
+
+ it "project_to knows it is forked" do
+ expect(project_to.forked?).to be_truthy
+ end
+
+ it "project_from is not forked" do
+ expect(project_from.forked?).to be_falsey
+ end
+
+ it "project_to.destroy destroys fork_link" do
+ project_to.destroy
+
+ expect(ForkedProjectLink.exists?(id: forked_project_link.id)).to eq(false)
+ end
end
-end
-def fork_project(from_project, user)
- shell = double('gitlab_shell', fork_repository: true)
+ def fork_project(from_project, user)
+ service = Projects::ForkService.new(from_project, user)
+ shell = double('gitlab_shell', fork_repository: true)
- service = Projects::ForkService.new(from_project, user)
- allow(service).to receive(:gitlab_shell).and_return(shell)
+ allow(service).to receive(:gitlab_shell).and_return(shell)
- service.execute
+ service.execute
+ end
end
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index 152e97e09bf..aedc74deb78 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GenericCommitStatus, models: true do
+describe GenericCommitStatus do
let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:external_url) { 'http://example.gitlab.com/status' }
diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb
index a14efda3eda..5584a1a5a31 100644
--- a/spec/models/global_milestone_spec.rb
+++ b/spec/models/global_milestone_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GlobalMilestone, models: true do
+describe GlobalMilestone do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
@@ -72,7 +72,7 @@ describe GlobalMilestone, models: true do
project3
]
- @global_milestones = GlobalMilestone.build_collection(projects, {})
+ @global_milestones = described_class.build_collection(projects, {})
end
it 'has all project milestones' do
@@ -106,7 +106,7 @@ describe GlobalMilestone, models: true do
it 'returns the quantity of global milestones in each possible state' do
expected_count = { opened: 1, closed: 2, all: 2 }
- count = GlobalMilestone.states_count(Project.all)
+ count = described_class.states_count(Project.all)
expect(count).to eq(expected_count)
end
@@ -120,7 +120,7 @@ describe GlobalMilestone, models: true do
it 'returns 0 as the quantity of global milestones in each state' do
expected_count = { opened: 0, closed: 0, all: 0 }
- count = GlobalMilestone.states_count(Project.all)
+ count = described_class.states_count(Project.all)
expect(count).to eq(expected_count)
end
@@ -141,7 +141,7 @@ describe GlobalMilestone, models: true do
]
milestones_relation = Milestone.where(id: milestones.map(&:id))
- @global_milestone = GlobalMilestone.new(milestone1_project1.title, milestones_relation)
+ @global_milestone = described_class.new(milestone1_project1.title, milestones_relation)
end
it 'has exactly one group milestone' do
@@ -157,7 +157,7 @@ describe GlobalMilestone, models: true do
let(:milestone) { create(:milestone, title: "git / test", project: project1) }
it 'strips out slashes and spaces' do
- global_milestone = GlobalMilestone.new(milestone.title, Milestone.where(id: milestone.id))
+ global_milestone = described_class.new(milestone.title, Milestone.where(id: milestone.id))
expect(global_milestone.safe_title).to eq('git-test')
end
@@ -171,7 +171,7 @@ describe GlobalMilestone, models: true do
create(:active_milestone, title: title),
create(:closed_milestone, title: title)
]
- global_milestone = GlobalMilestone.new(title, milestones)
+ global_milestone = described_class.new(title, milestones)
expect(global_milestone.state).to eq('active')
end
@@ -184,7 +184,7 @@ describe GlobalMilestone, models: true do
create(:closed_milestone, title: title),
create(:closed_milestone, title: title)
]
- global_milestone = GlobalMilestone.new(title, milestones)
+ global_milestone = described_class.new(title, milestones)
expect(global_milestone.state).to eq('closed')
end
diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb
new file mode 100644
index 00000000000..59c074199db
--- /dev/null
+++ b/spec/models/gpg_key_spec.rb
@@ -0,0 +1,157 @@
+require 'rails_helper'
+
+describe GpgKey do
+ describe "associations" do
+ it { is_expected.to belong_to(:user) }
+ end
+
+ describe "validation" do
+ it { is_expected.to validate_presence_of(:user) }
+
+ it { is_expected.to validate_presence_of(:key) }
+ it { is_expected.to validate_uniqueness_of(:key) }
+
+ it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey\n-----END PGP PUBLIC KEY BLOCK-----").for(:key) }
+
+ it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) }
+ it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey\n-----BEGIN PGP PUBLIC KEY BLOCK-----").for(:key) }
+ it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK----------END PGP PUBLIC KEY BLOCK-----").for(:key) }
+ it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----").for(:key) }
+ it { is_expected.not_to allow_value("-----END PGP PUBLIC KEY BLOCK-----").for(:key) }
+ it { is_expected.not_to allow_value("key\n-----END PGP PUBLIC KEY BLOCK-----").for(:key) }
+ it { is_expected.not_to allow_value('BEGIN PGP').for(:key) }
+ end
+
+ context 'callbacks' do
+ describe 'extract_fingerprint' do
+ it 'extracts the fingerprint from the gpg key' do
+ gpg_key = described_class.new(key: GpgHelpers::User1.public_key)
+ gpg_key.valid?
+ expect(gpg_key.fingerprint).to eq GpgHelpers::User1.fingerprint
+ end
+ end
+
+ describe 'extract_primary_keyid' do
+ it 'extracts the primary keyid from the gpg key' do
+ gpg_key = described_class.new(key: GpgHelpers::User1.public_key)
+ gpg_key.valid?
+ expect(gpg_key.primary_keyid).to eq GpgHelpers::User1.primary_keyid
+ end
+ end
+ end
+
+ describe '#key=' do
+ it 'strips white spaces' do
+ key = <<~KEY.strip
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
+ Version: GnuPG v1
+
+ mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP
+ -----END PGP PUBLIC KEY BLOCK-----
+ KEY
+
+ expect(described_class.new(key: " #{key} ").key).to eq(key)
+ end
+
+ it 'does not strip when the key is nil' do
+ expect(described_class.new(key: nil).key).to be_nil
+ end
+ end
+
+ describe '#user_infos' do
+ it 'returns the user infos from the gpg key' do
+ gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key
+ expect(Gitlab::Gpg).to receive(:user_infos_from_key).with(gpg_key.key)
+
+ gpg_key.user_infos
+ end
+ end
+
+ describe '#verified_user_infos' do
+ it 'returns the user infos if it is verified' do
+ user = create :user, email: GpgHelpers::User1.emails.first
+ gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user
+
+ expect(gpg_key.verified_user_infos).to eq([{
+ name: GpgHelpers::User1.names.first,
+ email: GpgHelpers::User1.emails.first
+ }])
+ end
+
+ it 'returns an empty array if the user info is not verified' do
+ user = create :user, email: 'unrelated@example.com'
+ gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user
+
+ expect(gpg_key.verified_user_infos).to eq([])
+ end
+ end
+
+ describe '#emails_with_verified_status' do
+ it 'email is verified if the user has the matching email' do
+ user = create :user, email: 'bette.cartwright@example.com'
+ gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user
+
+ expect(gpg_key.emails_with_verified_status).to eq(
+ 'bette.cartwright@example.com' => true,
+ 'bette.cartwright@example.net' => false
+ )
+ end
+ end
+
+ describe '#verified?' do
+ it 'returns true one of the email addresses in the key belongs to the user' do
+ user = create :user, email: 'bette.cartwright@example.com'
+ gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user
+
+ expect(gpg_key.verified?).to be_truthy
+ end
+
+ it 'returns false if one of the email addresses in the key does not belong to the user' do
+ user = create :user, email: 'someone.else@example.com'
+ gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user
+
+ expect(gpg_key.verified?).to be_falsey
+ end
+ end
+
+ describe 'notification' do
+ include EmailHelpers
+
+ let(:user) { create(:user) }
+
+ it 'sends a notification' do
+ perform_enqueued_jobs do
+ create(:gpg_key, user: user)
+ end
+
+ should_email(user)
+ end
+ end
+
+ describe '#revoke' do
+ it 'invalidates all associated gpg signatures and destroys the key' do
+ gpg_key = create :gpg_key
+ gpg_signature = create :gpg_signature, valid_signature: true, gpg_key: gpg_key
+
+ unrelated_gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key
+ unrelated_gpg_signature = create :gpg_signature, valid_signature: true, gpg_key: unrelated_gpg_key
+
+ gpg_key.revoke
+
+ expect(gpg_signature.reload).to have_attributes(
+ valid_signature: false,
+ gpg_key: nil
+ )
+
+ expect(gpg_key.destroyed?).to be true
+
+ # unrelated signature is left untouched
+ expect(unrelated_gpg_signature.reload).to have_attributes(
+ valid_signature: true,
+ gpg_key: unrelated_gpg_key
+ )
+
+ expect(unrelated_gpg_key.destroyed?).to be false
+ end
+ end
+end
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
new file mode 100644
index 00000000000..9a9b1900aa5
--- /dev/null
+++ b/spec/models/gpg_signature_spec.rb
@@ -0,0 +1,28 @@
+require 'rails_helper'
+
+RSpec.describe GpgSignature do
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:gpg_key) }
+ end
+
+ describe 'validation' do
+ subject { described_class.new }
+ it { is_expected.to validate_presence_of(:commit_sha) }
+ it { is_expected.to validate_presence_of(:project_id) }
+ it { is_expected.to validate_presence_of(:gpg_key_primary_keyid) }
+ end
+
+ describe '#commit' do
+ it 'fetches the commit through the project' do
+ commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
+ project = create :project
+ commit = create :commit, project: project
+ gpg_signature = create :gpg_signature, commit_sha: commit_sha
+
+ expect_any_instance_of(Project).to receive(:commit).with(commit_sha).and_return(commit)
+
+ gpg_signature.commit
+ end
+ end
+end
diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb
index 555a876daeb..f7828059295 100644
--- a/spec/models/group_label_spec.rb
+++ b/spec/models/group_label_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupLabel, models: true do
+describe GroupLabel do
describe 'relationships' do
it { is_expected.to belong_to(:group) }
end
diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb
index 916afb7aaf5..ac76c927c39 100644
--- a/spec/models/group_milestone_spec.rb
+++ b/spec/models/group_milestone_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupMilestone, models: true do
+describe GroupMilestone do
let(:group) { create(:group) }
let(:project) { create(:empty_project, group: group) }
let(:project_milestone) do
@@ -9,7 +9,7 @@ describe GroupMilestone, models: true do
describe '.build' do
it 'returns milestone with group assigned' do
- milestone = GroupMilestone.build(
+ milestone = described_class.build(
group,
[project],
project_milestone.title
@@ -25,7 +25,7 @@ describe GroupMilestone, models: true do
end
it 'returns array of milestones, each with group assigned' do
- milestones = GroupMilestone.build_collection(group, [project], {})
+ milestones = described_class.build_collection(group, [project], {})
expect(milestones).to all(have_attributes(group: group))
end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 4de1683b21c..112bd605a64 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Group, models: true do
+describe Group do
let!(:group) { create(:group, :access_requestable) }
describe 'associations' do
@@ -13,6 +13,7 @@ describe Group, models: true do
it { is_expected.to have_many(:shared_projects).through(:project_group_links) }
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
it { is_expected.to have_many(:labels).class_name('GroupLabel') }
+ it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
it { is_expected.to have_many(:uploads).dependent(:destroy) }
it { is_expected.to have_one(:chat_team) }
@@ -188,7 +189,7 @@ describe Group, models: true do
let!(:group) { create(:group, :access_requestable, :with_avatar) }
let(:user) { create(:user) }
let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
- let(:avatar_path) { "/uploads/system/group/avatar/#{group.id}/dk.png" }
+ let(:avatar_path) { "/uploads/-/system/group/avatar/#{group.id}/dk.png" }
context 'when avatar file is uploaded' do
before do
@@ -235,6 +236,7 @@ describe Group, models: true do
describe '#has_owner?' do
before do
@members = setup_group_members(group)
+ create(:group_member, :invited, :owner, group: group)
end
it { expect(group.has_owner?(@members[:owner])).to be_truthy }
@@ -243,11 +245,13 @@ describe Group, models: true do
it { expect(group.has_owner?(@members[:reporter])).to be_falsey }
it { expect(group.has_owner?(@members[:guest])).to be_falsey }
it { expect(group.has_owner?(@members[:requester])).to be_falsey }
+ it { expect(group.has_owner?(nil)).to be_falsey }
end
describe '#has_master?' do
before do
@members = setup_group_members(group)
+ create(:group_member, :invited, :master, group: group)
end
it { expect(group.has_master?(@members[:owner])).to be_falsey }
@@ -256,6 +260,7 @@ describe Group, models: true do
it { expect(group.has_master?(@members[:reporter])).to be_falsey }
it { expect(group.has_master?(@members[:guest])).to be_falsey }
it { expect(group.has_master?(@members[:requester])).to be_falsey }
+ it { expect(group.has_master?(nil)).to be_falsey }
end
describe '#lfs_enabled?' do
@@ -352,7 +357,7 @@ describe Group, models: true do
subject { build(:group, :nested) }
it { is_expected.to be_valid }
- it { expect(subject.parent).to be_kind_of(Group) }
+ it { expect(subject.parent).to be_kind_of(described_class) }
end
describe '#members_with_parents', :nested_groups do
@@ -418,4 +423,69 @@ describe Group, models: true do
expect(calls).to eq 2
end
end
+
+ describe '#secret_variables_for' do
+ let(:project) { create(:empty_project, group: group) }
+
+ let!(:secret_variable) do
+ create(:ci_group_variable, value: 'secret', group: group)
+ end
+
+ let!(:protected_variable) do
+ create(:ci_group_variable, :protected, value: 'protected', group: group)
+ end
+
+ subject { group.secret_variables_for('ref', project) }
+
+ shared_examples 'ref is protected' do
+ it 'contains all the variables' do
+ is_expected.to contain_exactly(secret_variable, protected_variable)
+ end
+ end
+
+ context 'when the ref is not protected' do
+ before do
+ stub_application_setting(
+ default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ end
+
+ it 'contains only the secret variables' do
+ is_expected.to contain_exactly(secret_variable)
+ end
+ end
+
+ context 'when the ref is a protected branch' do
+ before do
+ create(:protected_branch, name: 'ref', project: project)
+ end
+
+ it_behaves_like 'ref is protected'
+ end
+
+ context 'when the ref is a protected tag' do
+ before do
+ create(:protected_tag, name: 'ref', project: project)
+ end
+
+ it_behaves_like 'ref is protected'
+ end
+
+ context 'when group has children', :postgresql do
+ let(:group_child) { create(:group, parent: group) }
+ let(:group_child_2) { create(:group, parent: group_child) }
+ let(:group_child_3) { create(:group, parent: group_child_2) }
+ let(:variable_child) { create(:ci_group_variable, group: group_child) }
+ let(:variable_child_2) { create(:ci_group_variable, group: group_child_2) }
+ let(:variable_child_3) { create(:ci_group_variable, group: group_child_3) }
+
+ it 'returns all variables belong to the group and parent groups' do
+ expected_array1 = [protected_variable, secret_variable]
+ expected_array2 = [variable_child, variable_child_2, variable_child_3]
+ got_array = group_child_3.secret_variables_for('ref', project).to_a
+
+ expect(got_array.shift(2)).to contain_exactly(*expected_array1)
+ expect(got_array).to eq(expected_array2)
+ end
+ end
+ end
end
diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb
index c60bd7af958..0e9b94aac97 100644
--- a/spec/models/guest_spec.rb
+++ b/spec/models/guest_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Guest, lib: true do
+describe Guest do
let(:public_project) { build_stubbed(:empty_project, :public) }
let(:private_project) { build_stubbed(:empty_project, :private) }
let(:internal_project) { build_stubbed(:empty_project, :internal) }
@@ -8,13 +8,13 @@ describe Guest, lib: true do
describe '.can_pull?' do
context 'when project is private' do
it 'does not allow to pull the repo' do
- expect(Guest.can?(:download_code, private_project)).to eq(false)
+ expect(described_class.can?(:download_code, private_project)).to eq(false)
end
end
context 'when project is internal' do
it 'does not allow to pull the repo' do
- expect(Guest.can?(:download_code, internal_project)).to eq(false)
+ expect(described_class.can?(:download_code, internal_project)).to eq(false)
end
end
@@ -23,7 +23,7 @@ describe Guest, lib: true do
it 'does not allow to pull the repo' do
public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED)
- expect(Guest.can?(:download_code, public_project)).to eq(false)
+ expect(described_class.can?(:download_code, public_project)).to eq(false)
end
end
@@ -31,13 +31,13 @@ describe Guest, lib: true do
it 'does not allow to pull the repo' do
public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::PRIVATE)
- expect(Guest.can?(:download_code, public_project)).to eq(false)
+ expect(described_class.can?(:download_code, public_project)).to eq(false)
end
end
context 'when repository is enabled' do
it 'allows to pull the repo' do
- expect(Guest.can?(:download_code, public_project)).to eq(true)
+ expect(described_class.can?(:download_code, public_project)).to eq(true)
end
end
end
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index 474ae62ccec..5dd31b1b5de 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -1,15 +1,19 @@
require 'spec_helper'
-describe ProjectHook, models: true do
- describe "Associations" do
+describe ProjectHook do
+ describe 'associations' do
it { is_expected.to belong_to :project }
end
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project) }
+ end
+
describe '.push_hooks' do
it 'returns hooks for push events only' do
hook = create(:project_hook, push_events: true)
create(:project_hook, push_events: false)
- expect(ProjectHook.push_hooks).to eq([hook])
+ expect(described_class.push_hooks).to eq([hook])
end
end
@@ -17,7 +21,7 @@ describe ProjectHook, models: true do
it 'returns hooks for tag push events only' do
hook = create(:project_hook, tag_push_events: true)
create(:project_hook, tag_push_events: false)
- expect(ProjectHook.tag_push_hooks).to eq([hook])
+ expect(described_class.tag_push_hooks).to eq([hook])
end
end
end
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index 57454d2a773..e32eaafc13f 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -1,10 +1,14 @@
require 'spec_helper'
-describe ServiceHook, models: true do
+describe ServiceHook do
describe 'associations' do
it { is_expected.to belong_to :service }
end
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:service) }
+ end
+
describe 'execute' do
let(:hook) { build(:service_hook) }
let(:data) { { key: 'value' } }
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index 0d2b622132e..eadc232a989 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -1,14 +1,13 @@
require "spec_helper"
-describe SystemHook, models: true do
+describe SystemHook do
context 'default attributes' do
let(:system_hook) { build(:system_hook) }
it 'sets defined default parameters' do
attrs = {
push_events: false,
- repository_update_events: true,
- enable_ssl_verification: true
+ repository_update_events: true
}
expect(system_hook).to have_attributes(attrs)
end
@@ -123,7 +122,7 @@ describe SystemHook, models: true do
it 'returns hooks for repository update events only' do
hook = create(:system_hook, repository_update_events: true)
create(:system_hook, repository_update_events: false)
- expect(SystemHook.repository_update_hooks).to eq([hook])
+ expect(described_class.repository_update_hooks).to eq([hook])
end
end
diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb
index c649cf3b589..19bc88b1333 100644
--- a/spec/models/hooks/web_hook_log_spec.rb
+++ b/spec/models/hooks/web_hook_log_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe WebHookLog, models: true do
+describe WebHookLog do
it { is_expected.to belong_to(:web_hook) }
it { is_expected.to serialize(:request_headers).as(Hash) }
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 53157c24477..388120160ab 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe WebHook, models: true do
+describe WebHook do
let(:hook) { build(:project_hook) }
describe 'associations' do
diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb
index b3aed66a5b6..4ca6556d0f4 100644
--- a/spec/models/identity_spec.rb
+++ b/spec/models/identity_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-RSpec.describe Identity, models: true do
+RSpec.describe Identity do
describe 'relations' do
it { is_expected.to belong_to(:user) }
end
diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb
index 08712f2a768..6ceff7d24d4 100644
--- a/spec/models/issue/metrics_spec.rb
+++ b/spec/models/issue/metrics_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issue::Metrics, models: true do
+describe Issue::Metrics do
let(:project) { create(:empty_project) }
subject { create(:issue, project: project) }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index bf97c6ececd..d72790eefe5 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issue, models: true do
+describe Issue do
describe "Associations" do
it { is_expected.to belong_to(:milestone) }
it { is_expected.to have_many(:assignees) }
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index f27920f9feb..d41717d0223 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Key, models: true do
+describe Key do
include EmailHelpers
describe "Associations" do
diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb
index c18ed8574b1..e2b49bc2de7 100644
--- a/spec/models/label_link_spec.rb
+++ b/spec/models/label_link_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe LabelLink, models: true do
+describe LabelLink do
it { expect(build(:label_link)).to be_valid }
it { is_expected.to belong_to(:label) }
diff --git a/spec/models/label_priority_spec.rb b/spec/models/label_priority_spec.rb
index d18c2f7949a..9dcb0f06b20 100644
--- a/spec/models/label_priority_spec.rb
+++ b/spec/models/label_priority_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe LabelPriority, models: true do
+describe LabelPriority do
describe 'relationships' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:label) }
diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb
index 31190fe5685..8914845ea82 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Label, models: true do
+describe Label do
describe 'modules' do
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Subscribable) }
diff --git a/spec/models/legacy_diff_discussion_spec.rb b/spec/models/legacy_diff_discussion_spec.rb
index 6eb4a2aaf39..dae97b69c84 100644
--- a/spec/models/legacy_diff_discussion_spec.rb
+++ b/spec/models/legacy_diff_discussion_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe LegacyDiffDiscussion, models: true do
+describe LegacyDiffDiscussion do
subject { create(:legacy_diff_note_on_merge_request).to_discussion }
describe '#reply_attributes' do
diff --git a/spec/models/lfs_objects_project_spec.rb b/spec/models/lfs_objects_project_spec.rb
index 7bc278e350f..8c74f1f9e86 100644
--- a/spec/models/lfs_objects_project_spec.rb
+++ b/spec/models/lfs_objects_project_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe LfsObjectsProject, models: true do
+describe LfsObjectsProject do
subject { create(:lfs_objects_project, project: project) }
let(:project) { create(:empty_project) }
diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb
index db2c2619968..a6cc01bea5f 100644
--- a/spec/models/list_spec.rb
+++ b/spec/models/list_spec.rb
@@ -13,12 +13,6 @@ describe List do
it { is_expected.to validate_presence_of(:position) }
it { is_expected.to validate_numericality_of(:position).only_integer.is_greater_than_or_equal_to(0) }
- it 'validates uniqueness of label scoped to board_id' do
- create(:list)
-
- expect(subject).to validate_uniqueness_of(:label_id).scoped_to(:board_id)
- end
-
context 'when list_type is set to closed' do
subject { described_class.new(list_type: :closed) }
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 494a88368ba..8bfd70b8d46 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe Member, models: true do
+describe Member do
describe "Associations" do
it { is_expected.to belong_to(:user) }
end
describe "Validation" do
- subject { Member.new(access_level: Member::GUEST) }
+ subject { described_class.new(access_level: Member::GUEST) }
it { is_expected.to validate_presence_of(:user) }
it { is_expected.to validate_presence_of(:source) }
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 37014268a70..5a3b5b1f517 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupMember, models: true do
+describe GroupMember do
describe '.access_level_roles' do
it 'returns Gitlab::Access.options_with_owner' do
expect(described_class.access_level_roles).to eq(Gitlab::Access.options_with_owner)
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index cf9c701e8c5..025fb2bf441 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectMember, models: true do
+describe ProjectMember do
describe 'associations' do
it { is_expected.to belong_to(:project).with_foreign_key(:source_id) }
end
@@ -139,7 +139,7 @@ describe ProjectMember, models: true do
@project_1.team << [@user_1, :developer]
@project_2.team << [@user_2, :reporter]
- ProjectMember.truncate_teams([@project_1.id, @project_2.id])
+ described_class.truncate_teams([@project_1.id, @project_2.id])
end
it { expect(@project_1.users).to be_empty }
diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb
index 9afed311e27..9353d5c3c8a 100644
--- a/spec/models/merge_request/metrics_spec.rb
+++ b/spec/models/merge_request/metrics_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequest::Metrics, models: true do
+describe MergeRequest::Metrics do
subject { create(:merge_request) }
describe "when recording the default set of metrics on merge request save" do
diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb
new file mode 100644
index 00000000000..9d4a0ecf8c0
--- /dev/null
+++ b/spec/models/merge_request_diff_commit_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+describe MergeRequestDiffCommit do
+ let(:merge_request) { create(:merge_request) }
+ subject { merge_request.commits.first }
+
+ describe '#to_hash' do
+ it 'returns the same results as Commit#to_hash, except for parent_ids' do
+ commit_from_repo = merge_request.project.repository.commit(subject.sha)
+ commit_from_repo_hash = commit_from_repo.to_hash.merge(parent_ids: [])
+
+ expect(subject.to_hash).to eq(commit_from_repo_hash)
+ end
+ end
+end
diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb
index 7276f5b5061..faa47660a74 100644
--- a/spec/models/merge_request_diff_file_spec.rb
+++ b/spec/models/merge_request_diff_file_spec.rb
@@ -1,8 +1,33 @@
require 'rails_helper'
-describe MergeRequestDiffFile, type: :model do
+describe MergeRequestDiffFile do
+ describe '#diff' do
+ let(:unpacked) { 'unpacked' }
+ let(:packed) { [unpacked].pack('m0') }
+
+ before do
+ subject.diff = packed
+ end
+
+ context 'when the diff is marked as binary' do
+ before do
+ subject.binary = true
+ end
+
+ it 'unpacks from base 64' do
+ expect(subject.diff).to eq(unpacked)
+ end
+ end
+
+ context 'when the diff is not marked as binary' do
+ it 'returns the raw diff' do
+ expect(subject.diff).to eq(packed)
+ end
+ end
+ end
+
describe '#utf8_diff' do
- it 'does not raise error when a hash value is in binary' do
+ it 'does not raise error when the diff is binary' do
subject.diff = "\x05\x00\x68\x65\x6c\x6c\x6f"
expect { subject.utf8_diff }.not_to raise_error
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index 4ad4abaa572..0cfaa17676e 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequestDiff, models: true do
+describe MergeRequestDiff do
describe 'create new record' do
subject { create(:merge_request).merge_request_diff }
@@ -98,23 +98,32 @@ describe MergeRequestDiff, models: true do
end
it 'saves empty state' do
- allow_any_instance_of(MergeRequestDiff).to receive(:commits)
+ allow_any_instance_of(described_class).to receive_message_chain(:compare, :commits)
.and_return([])
mr_diff = create(:merge_request).merge_request_diff
expect(mr_diff.empty?).to be_truthy
end
+
+ it 'saves binary diffs correctly' do
+ path = 'files/images/icn-time-tracking.pdf'
+ mr_diff = create(:merge_request, source_branch: 'add-pdf-text-binary', target_branch: 'master').merge_request_diff
+ diff_file = mr_diff.merge_request_diff_files.find_by(new_path: path)
+
+ expect(diff_file).to be_binary
+ expect(diff_file.diff).to eq(mr_diff.compare.diffs(paths: [path]).to_a.first.diff)
+ end
end
- describe '#commits_sha' do
+ describe '#commit_shas' do
it 'returns all commits SHA using serialized commits' do
subject.st_commits = [
{ id: 'sha1' },
{ id: 'sha2' }
]
- expect(subject.commits_sha).to eq(%w(sha1 sha2))
+ expect(subject.commit_shas).to eq(%w(sha1 sha2))
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 1240c9745e2..b2dd02553c1 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequest, models: true do
+describe MergeRequest do
include RepoHelpers
subject { create(:merge_request) }
@@ -10,7 +10,7 @@ describe MergeRequest, models: true do
it { is_expected.to belong_to(:source_project).class_name('Project') }
it { is_expected.to belong_to(:merge_user).class_name("User") }
it { is_expected.to belong_to(:assignee) }
- it { is_expected.to have_many(:merge_request_diffs).dependent(:destroy) }
+ it { is_expected.to have_many(:merge_request_diffs) }
end
describe 'modules' do
@@ -105,6 +105,22 @@ describe MergeRequest, models: true do
end
end
+ describe '#assignee_ids' do
+ it 'returns an array of the assigned user id' do
+ subject.assignee_id = 123
+
+ expect(subject.assignee_ids).to eq([123])
+ end
+ end
+
+ describe '#assignee_ids=' do
+ it 'sets assignee_id to the last id in the array' do
+ subject.assignee_ids = [123, 456]
+
+ expect(subject.assignee_id).to eq(456)
+ end
+ end
+
describe '#assignee_or_author?' do
let(:user) { create(:user) }
@@ -139,13 +155,53 @@ describe MergeRequest, models: true do
expect { subject.cache_merge_request_closes_issues!(subject.author) }.to change(subject.merge_requests_closing_issues, :count).by(1)
end
- it 'does not cache issues from external trackers' do
- subject.project.update_attribute(:has_external_issue_tracker, true)
- issue = ExternalIssue.new('JIRA-123', subject.project)
- commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
- allow(subject).to receive(:commits).and_return([commit])
+ context 'when both internal and external issue trackers are enabled' do
+ before do
+ subject.project.has_external_issue_tracker = true
+ subject.project.save!
+ end
+
+ it 'does not cache issues from external trackers' do
+ issue = ExternalIssue.new('JIRA-123', subject.project)
+ commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
+ allow(subject).to receive(:commits).and_return([commit])
+
+ expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count)
+ end
+
+ it 'caches an internal issue' do
+ issue = create(:issue, project: subject.project)
+ commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
+ allow(subject).to receive(:commits).and_return([commit])
+
+ expect { subject.cache_merge_request_closes_issues!(subject.author) }
+ .to change(subject.merge_requests_closing_issues, :count).by(1)
+ end
+ end
+
+ context 'when only external issue tracker enabled' do
+ before do
+ subject.project.has_external_issue_tracker = true
+ subject.project.issues_enabled = false
+ subject.project.save!
+ end
+
+ it 'does not cache issues from external trackers' do
+ issue = ExternalIssue.new('JIRA-123', subject.project)
+ commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
+ allow(subject).to receive(:commits).and_return([commit])
+
+ expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count)
+ end
+
+ it 'does not cache an internal issue' do
+ issue = create(:issue, project: subject.project)
+ commit = double('commit1', safe_message: "Fixes #{issue.to_reference}")
+ allow(subject).to receive(:commits).and_return([commit])
- expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count)
+ expect { subject.cache_merge_request_closes_issues!(subject.author) }
+ .not_to change(subject.merge_requests_closing_issues, :count)
+ end
end
end
@@ -704,14 +760,14 @@ describe MergeRequest, models: true do
subject { create :merge_request, :simple }
end
- describe '#commits_sha' do
+ describe '#commit_shas' do
before do
- allow(subject.merge_request_diff).to receive(:commits_sha)
+ allow(subject.merge_request_diff).to receive(:commit_shas)
.and_return(['sha1'])
end
it 'delegates to merge request diff' do
- expect(subject.commits_sha).to eq ['sha1']
+ expect(subject.commit_shas).to eq ['sha1']
end
end
@@ -736,7 +792,7 @@ describe MergeRequest, models: true do
describe '#all_pipelines' do
shared_examples 'returning pipelines with proper ordering' do
let!(:all_pipelines) do
- subject.all_commits_sha.map do |sha|
+ subject.all_commit_shas.map do |sha|
create(:ci_empty_pipeline,
project: subject.source_project,
sha: sha,
@@ -778,16 +834,16 @@ describe MergeRequest, models: true do
end
end
- describe '#all_commits_sha' do
+ describe '#all_commit_shas' do
context 'when merge request is persisted' do
- let(:all_commits_sha) do
+ let(:all_commit_shas) do
subject.merge_request_diffs.flat_map(&:commits).map(&:sha).uniq
end
shared_examples 'returning all SHA' do
it 'returns all SHA from all merge_request_diffs' do
expect(subject.merge_request_diffs.size).to eq(2)
- expect(subject.all_commits_sha).to eq(all_commits_sha)
+ expect(subject.all_commit_shas).to match_array(all_commit_shas)
end
end
@@ -818,7 +874,7 @@ describe MergeRequest, models: true do
end
it 'returns commits from compare commits temporary data' do
- expect(subject.all_commits_sha).to eq [commit, commit]
+ expect(subject.all_commit_shas).to eq [commit, commit]
end
end
@@ -826,7 +882,7 @@ describe MergeRequest, models: true do
subject { build(:merge_request) }
it 'returns array with diff head sha element only' do
- expect(subject.all_commits_sha).to eq [subject.diff_head_sha]
+ expect(subject.all_commit_shas).to eq [subject.diff_head_sha]
end
end
end
@@ -1574,4 +1630,40 @@ describe MergeRequest, models: true do
end
end
end
+
+ describe '#fetch_ref' do
+ it 'sets "ref_fetched" flag to true' do
+ subject.update!(ref_fetched: nil)
+
+ subject.fetch_ref
+
+ expect(subject.reload.ref_fetched).to be_truthy
+ end
+ end
+
+ describe '#ref_fetched?' do
+ it 'does not perform git operation when value is cached' do
+ subject.ref_fetched = true
+
+ expect_any_instance_of(Repository).not_to receive(:ref_exists?)
+ expect(subject.ref_fetched?).to be_truthy
+ end
+
+ it 'caches the value when ref exists but value is not cached' do
+ subject.update!(ref_fetched: nil)
+ allow_any_instance_of(Repository).to receive(:ref_exists?)
+ .and_return(true)
+
+ expect(subject.ref_fetched?).to be_truthy
+ expect(subject.reload.ref_fetched).to be_truthy
+ end
+
+ it 'returns false when ref does not exist' do
+ subject.update!(ref_fetched: nil)
+ allow_any_instance_of(Repository).to receive(:ref_exists?)
+ .and_return(false)
+
+ expect(subject.ref_fetched?).to be_falsey
+ end
+ end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 45953023a36..aa376e242e8 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -1,14 +1,11 @@
require 'spec_helper'
-describe Milestone, models: true do
+describe Milestone do
describe "Validation" do
before do
allow(subject).to receive(:set_iid).and_return(false)
end
- it { is_expected.to validate_presence_of(:title) }
- it { is_expected.to validate_presence_of(:project) }
-
describe 'start_date' do
it 'adds an error when start_date is greated then due_date' do
milestone = build(:milestone, start_date: Date.tomorrow, due_date: Date.yesterday)
@@ -37,17 +34,42 @@ describe Milestone, models: true do
end
end
- describe "unique milestone title per project" do
- it "does not accept the same title in a project twice" do
- new_milestone = Milestone.new(project: milestone.project, title: milestone.title)
- expect(new_milestone).not_to be_valid
+ describe "unique milestone title" do
+ context "per project" do
+ it "does not accept the same title in a project twice" do
+ new_milestone = described_class.new(project: milestone.project, title: milestone.title)
+ expect(new_milestone).not_to be_valid
+ end
+
+ it "accepts the same title in another project" do
+ project = create(:empty_project)
+ new_milestone = described_class.new(project: project, title: milestone.title)
+
+ expect(new_milestone).to be_valid
+ end
end
- it "accepts the same title in another project" do
- project = build(:empty_project)
- new_milestone = Milestone.new(project: project, title: milestone.title)
+ context "per group" do
+ let(:group) { create(:group) }
+ let(:milestone) { create(:milestone, group: group) }
+
+ before do
+ project.update(group: group)
+ end
+
+ it "does not accept the same title in a group twice" do
+ new_milestone = described_class.new(group: group, title: milestone.title)
+
+ expect(new_milestone).not_to be_valid
+ end
- expect(new_milestone).to be_valid
+ it "does not accept the same title of a child project milestone" do
+ create(:milestone, project: group.projects.first)
+
+ new_milestone = described_class.new(group: group, title: milestone.title)
+
+ expect(new_milestone).not_to be_valid
+ end
end
end
@@ -192,7 +214,7 @@ describe Milestone, models: true do
# The call to `#try` is because this returns a relation with a Postgres DB,
# and an array of IDs with a MySQL DB.
- let(:milestone_ids) { Milestone.upcoming_ids_by_projects(projects).map { |id| id.try(:id) || id } }
+ let(:milestone_ids) { described_class.upcoming_ids_by_projects(projects).map { |id| id.try(:id) || id } }
it 'returns the next upcoming open milestone ID for each project' do
expect(milestone_ids).to contain_exactly(current_milestone_project_1.id, current_milestone_project_2.id)
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index e7c3acf19eb..f12fe226e6b 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Namespace, models: true do
+describe Namespace do
let!(:namespace) { create(:namespace) }
describe 'associations' do
@@ -44,7 +44,7 @@ describe Namespace, models: true do
end
context "is case insensitive" do
- let(:group) { build(:group, path: "System") }
+ let(:group) { build(:group, path: "Groups") }
it { expect(group).not_to be_valid }
end
@@ -63,6 +63,14 @@ describe Namespace, models: true do
it { is_expected.to respond_to(:has_parent?) }
end
+ describe 'inclusions' do
+ it { is_expected.to include_module(Gitlab::VisibilityLevel) }
+ end
+
+ describe '#visibility_level_field' do
+ it { expect(namespace.visibility_level_field).to eq(:visibility_level) }
+ end
+
describe '#to_param' do
it { expect(namespace.to_param).to eq(namespace.full_path) }
end
@@ -125,7 +133,7 @@ describe Namespace, models: true do
it "sums all project storage counters in the namespace" do
project1
project2
- statistics = Namespace.with_statistics.find(namespace.id)
+ statistics = described_class.with_statistics.find(namespace.id)
expect(statistics.storage_size).to eq 666
expect(statistics.repository_size).to eq 111
@@ -134,7 +142,7 @@ describe Namespace, models: true do
end
it "correctly handles namespaces without projects" do
- statistics = Namespace.with_statistics.find(namespace.id)
+ statistics = described_class.with_statistics.find(namespace.id)
expect(statistics.storage_size).to eq 0
expect(statistics.repository_size).to eq 0
@@ -143,7 +151,7 @@ describe Namespace, models: true do
end
end
- describe '#move_dir', repository: true do
+ describe '#move_dir' do
before do
@namespace = create :namespace
@project = create(:project_empty_repo, namespace: @namespace)
@@ -222,7 +230,7 @@ describe Namespace, models: true do
end
end
- describe '#rm_dir', 'callback', repository: true do
+ describe '#rm_dir', 'callback' do
let!(:project) { create(:project_empty_repo, namespace: namespace) }
let(:repository_storage_path) { Gitlab.config.repositories.storages.default['path'] }
let(:path_in_dir) { File.join(repository_storage_path, namespace.full_path) }
@@ -278,9 +286,9 @@ describe Namespace, models: true do
@namespace = create(:namespace, name: 'WoW', path: 'woW')
end
- it { expect(Namespace.find_by_path_or_name('wow')).to eq(@namespace) }
- it { expect(Namespace.find_by_path_or_name('WOW')).to eq(@namespace) }
- it { expect(Namespace.find_by_path_or_name('unknown')).to eq(nil) }
+ it { expect(described_class.find_by_path_or_name('wow')).to eq(@namespace) }
+ it { expect(described_class.find_by_path_or_name('WOW')).to eq(@namespace) }
+ it { expect(described_class.find_by_path_or_name('unknown')).to eq(nil) }
end
describe ".clean_path" do
@@ -288,8 +296,8 @@ describe Namespace, models: true do
let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") }
it "cleans the path and makes sure it's available" do
- expect(Namespace.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
- expect(Namespace.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name")
+ expect(described_class.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
+ expect(described_class.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name")
end
end
@@ -323,6 +331,36 @@ describe Namespace, models: true do
end
end
+ describe '#users_with_descendants', :nested_groups do
+ let(:user_a) { create(:user) }
+ let(:user_b) { create(:user) }
+
+ let(:group) { create(:group) }
+ let(:nested_group) { create(:group, parent: group) }
+ let(:deep_nested_group) { create(:group, parent: nested_group) }
+
+ it 'returns member users on every nest level without duplication' do
+ group.add_developer(user_a)
+ nested_group.add_developer(user_b)
+ deep_nested_group.add_developer(user_a)
+
+ expect(group.users_with_descendants).to contain_exactly(user_a, user_b)
+ expect(nested_group.users_with_descendants).to contain_exactly(user_a, user_b)
+ expect(deep_nested_group.users_with_descendants).to contain_exactly(user_a)
+ end
+ end
+
+ describe '#soft_delete_without_removing_associations' do
+ let(:project1) { create(:project_empty_repo, namespace: namespace) }
+
+ it 'updates the deleted_at timestamp but preserves projects' do
+ namespace.soft_delete_without_removing_associations
+
+ expect(Project.all).to include(project1)
+ expect(namespace.deleted_at).not_to be_nil
+ end
+ end
+
describe '#user_ids_for_project_authorizations' do
it 'returns the user IDs for which to refresh authorizations' do
expect(namespace.user_ids_for_project_authorizations)
diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb
index 0fe8a591a45..c364dd6643b 100644
--- a/spec/models/network/graph_spec.rb
+++ b/spec/models/network/graph_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Network::Graph, models: true do
+describe Network::Graph do
let(:project) { create(:project, :repository) }
let!(:note_on_commit) { create(:note_on_commit, project: project) }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index e2b80cb6e61..cbe6d42ef53 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Note, models: true do
+describe Note do
include RepoHelpers
describe 'associations' do
@@ -525,7 +525,7 @@ describe Note, models: true do
it "has a discussion id" do
# The discussion_id is set in `after_initialize`, so `reload` won't work
- reloaded_note = Note.find(note.id)
+ reloaded_note = described_class.find(note.id)
expect(reloaded_note.discussion_id).not_to be_nil
expect(reloaded_note.discussion_id).to match(/\A\h{40}\z/)
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index cc235ad467e..07e296424ca 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -1,21 +1,28 @@
require 'rails_helper'
-RSpec.describe NotificationSetting, type: :model do
+RSpec.describe NotificationSetting do
describe "Associations" do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:source) }
end
describe "Validation" do
- subject { NotificationSetting.new(source_id: 1, source_type: 'Project') }
+ subject { described_class.new(source_id: 1, source_type: 'Project') }
it { is_expected.to validate_presence_of(:user) }
it { is_expected.to validate_presence_of(:level) }
- it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_id, :source_type]).with_message(/already exists in source/) }
+
+ describe 'user_id' do
+ before do
+ subject.user = create(:user)
+ end
+
+ it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_type, :source_id]).with_message(/already exists in source/) }
+ end
context "events" do
let(:user) { create(:user) }
- let(:notification_setting) { NotificationSetting.new(source_id: 1, source_type: 'Project', user_id: user.id) }
+ let(:notification_setting) { described_class.new(source_id: 1, source_type: 'Project', user_id: user.id) }
before do
notification_setting.level = "custom"
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index f9d060d4e0e..7d835511dfb 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe PagesDomain, models: true do
+describe PagesDomain do
describe 'associations' do
it { is_expected.to belong_to(:project) }
end
@@ -11,7 +11,7 @@ describe PagesDomain, models: true do
context 'is unique' do
let(:domain) { 'my.domain.com' }
- it { is_expected.to validate_uniqueness_of(:domain) }
+ it { is_expected.to validate_uniqueness_of(:domain).case_insensitive }
end
{
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index fa781195608..b2f2a3ce914 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe PersonalAccessToken, models: true do
+describe PersonalAccessToken do
describe '.build' do
let(:personal_access_token) { build(:personal_access_token) }
let(:invalid_personal_access_token) { build(:personal_access_token, :invalid) }
diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb
index 4161b9158b1..d68d8b719cd 100644
--- a/spec/models/project_group_link_spec.rb
+++ b/spec/models/project_group_link_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe ProjectGroupLink do
describe "Associations" do
- it { should belong_to(:group) }
- it { should belong_to(:project) }
+ it { is_expected.to belong_to(:group) }
+ it { is_expected.to belong_to(:project) }
end
describe "Validation" do
@@ -12,10 +12,10 @@ describe ProjectGroupLink do
let(:project) { create(:project, group: group) }
let!(:project_group_link) { create(:project_group_link, project: project) }
- it { should validate_presence_of(:project_id) }
- it { should validate_uniqueness_of(:group_id).scoped_to(:project_id).with_message(/already shared/) }
- it { should validate_presence_of(:group) }
- it { should validate_presence_of(:group_access) }
+ it { is_expected.to validate_presence_of(:project_id) }
+ it { is_expected.to validate_uniqueness_of(:group_id).scoped_to(:project_id).with_message(/already shared/) }
+ it { is_expected.to validate_presence_of(:group) }
+ it { is_expected.to validate_presence_of(:group_access) }
it "doesn't allow a project to be shared with the group it is in" do
project_group_link.group = group
diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb
index 9cdbfa44e5b..add7e85f388 100644
--- a/spec/models/project_label_spec.rb
+++ b/spec/models/project_label_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectLabel, models: true do
+describe ProjectLabel do
describe 'relationships' do
it { is_expected.to belong_to(:project) }
end
diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb
index 95c35162d96..4684c970885 100644
--- a/spec/models/project_services/asana_service_spec.rb
+++ b/spec/models/project_services/asana_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe AsanaService, models: true do
+describe AsanaService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -35,7 +35,7 @@ describe AsanaService, models: true do
end
before do
- @asana = AsanaService.new
+ @asana = described_class.new
allow(@asana).to receive_messages(
project: project,
project_id: project.id,
diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb
index 96f00af898e..5cb6d63659e 100644
--- a/spec/models/project_services/assembla_service_spec.rb
+++ b/spec/models/project_services/assembla_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe AssemblaService, models: true do
+describe AssemblaService do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -11,7 +11,7 @@ describe AssemblaService, models: true do
let(:project) { create(:project, :repository) }
before do
- @assembla_service = AssemblaService.new
+ @assembla_service = described_class.new
allow(@assembla_service).to receive_messages(
project_id: project.id,
project: project,
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index e62fd69e567..82f02126de1 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BambooService, models: true, caching: true do
+describe BambooService, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers
let(:bamboo_url) { 'http://gitlab.com/bamboo' }
@@ -217,13 +217,13 @@ describe BambooService, models: true, caching: true do
end
def stub_request(status: 200, body: nil)
- bamboo_full_url = 'http://mic:password@gitlab.com/bamboo/rest/api/latest/result?label=123&os_authType=basic'
+ bamboo_full_url = 'http://gitlab.com/bamboo/rest/api/latest/result?label=123&os_authType=basic'
WebMock.stub_request(:get, bamboo_full_url).to_return(
status: status,
headers: { 'Content-Type' => 'application/json' },
body: body
- )
+ ).with(basic_auth: %w(mic password))
end
def bamboo_response(result_key: 42, build_state: 'success', size: 1)
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 5f17bbde390..43f7bcb1a19 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BugzillaService, models: true do
+describe BugzillaService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index dd529597067..3f7eb33e08a 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BuildkiteService, models: true, caching: true do
+describe BuildkiteService, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers
let(:project) { create(:empty_project) }
diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb
index de55627dd27..ed8347edffd 100644
--- a/spec/models/project_services/campfire_service_spec.rb
+++ b/spec/models/project_services/campfire_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CampfireService, models: true do
+describe CampfireService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -29,7 +29,7 @@ describe CampfireService, models: true do
let(:project) { create(:project, :repository) }
before do
- @campfire_service = CampfireService.new
+ @campfire_service = described_class.new
allow(@campfire_service).to receive_messages(
project_id: project.id,
project: project,
@@ -39,21 +39,22 @@ describe CampfireService, models: true do
room: 'test-room'
)
@sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
- @rooms_url = 'https://verySecret:X@project-name.campfirenow.com/rooms.json'
+ @rooms_url = 'https://project-name.campfirenow.com/rooms.json'
+ @auth = %w(verySecret X)
@headers = { 'Content-Type' => 'application/json; charset=utf-8' }
end
it "calls Campfire API to get a list of rooms and speak in a room" do
# make sure a valid list of rooms is returned
body = File.read(Rails.root + 'spec/fixtures/project_services/campfire/rooms.json')
- WebMock.stub_request(:get, @rooms_url).to_return(
+ WebMock.stub_request(:get, @rooms_url).with(basic_auth: @auth).to_return(
body: body,
status: 200,
headers: @headers
)
# stub the speak request with the room id found in the previous request's response
- speak_url = 'https://verySecret:X@project-name.campfirenow.com/room/123/speak.json'
- WebMock.stub_request(:post, speak_url)
+ speak_url = 'https://project-name.campfirenow.com/room/123/speak.json'
+ WebMock.stub_request(:post, speak_url).with(basic_auth: @auth)
@campfire_service.execute(@sample_data)
@@ -66,7 +67,7 @@ describe CampfireService, models: true do
it "calls Campfire API to get a list of rooms but shouldn't speak in a room" do
# return a list of rooms that do not contain a room named 'test-room'
body = File.read(Rails.root + 'spec/fixtures/project_services/campfire/rooms2.json')
- WebMock.stub_request(:get, @rooms_url).to_return(
+ WebMock.stub_request(:get, @rooms_url).with(basic_auth: @auth).to_return(
body: body,
status: 200,
headers: @headers
diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb
index c159ab00ab1..4bb1db684e6 100644
--- a/spec/models/project_services/chat_message/issue_message_spec.rb
+++ b/spec/models/project_services/chat_message/issue_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatMessage::IssueMessage, models: true do
+describe ChatMessage::IssueMessage do
subject { described_class.new(args) }
let(:args) do
diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb
index 61f17031172..b600a36f578 100644
--- a/spec/models/project_services/chat_message/merge_message_spec.rb
+++ b/spec/models/project_services/chat_message/merge_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatMessage::MergeMessage, models: true do
+describe ChatMessage::MergeMessage do
subject { described_class.new(args) }
let(:args) do
diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb
index 7996536218a..a09c2f9935c 100644
--- a/spec/models/project_services/chat_message/note_message_spec.rb
+++ b/spec/models/project_services/chat_message/note_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatMessage::NoteMessage, models: true do
+describe ChatMessage::NoteMessage do
subject { described_class.new(args) }
let(:color) { '#345' }
diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb
index c794f659c41..19c2862264f 100644
--- a/spec/models/project_services/chat_message/push_message_spec.rb
+++ b/spec/models/project_services/chat_message/push_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatMessage::PushMessage, models: true do
+describe ChatMessage::PushMessage do
subject { described_class.new(args) }
let(:args) do
diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
index 17355c1e6f1..c4adee4f489 100644
--- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb
+++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatMessage::WikiPageMessage, models: true do
+describe ChatMessage::WikiPageMessage do
subject { described_class.new(args) }
let(:args) do
diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb
index 8fbe42248ae..413ceed73bf 100644
--- a/spec/models/project_services/chat_notification_service_spec.rb
+++ b/spec/models/project_services/chat_notification_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatNotificationService, models: true do
+describe ChatNotificationService do
describe 'Associations' do
before do
allow(subject).to receive(:activated?).and_return(true)
diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb
index 9e574762232..7e1b1a4f2af 100644
--- a/spec/models/project_services/custom_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CustomIssueTrackerService, models: true do
+describe CustomIssueTrackerService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index 1400175427f..5b0f24ce306 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DroneCiService, models: true, caching: true do
+describe DroneCiService, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers
describe 'associations' do
diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb
index 291fc645a1c..22cd9d5e31e 100644
--- a/spec/models/project_services/external_wiki_service_spec.rb
+++ b/spec/models/project_services/external_wiki_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe ExternalWikiService, models: true do
+describe ExternalWikiService do
include ExternalWikiHelper
describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
end
describe 'Validations' do
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index 56ace04dd58..5e8e880985e 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe FlowdockService, models: true do
+describe FlowdockService do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -29,7 +29,7 @@ describe FlowdockService, models: true do
let(:project) { create(:project, :repository) }
before do
- @flowdock_service = FlowdockService.new
+ @flowdock_service = described_class.new
allow(@flowdock_service).to receive_messages(
project_id: project.id,
project: project,
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index 65c9e714bd1..4c61bc0af95 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GemnasiumService, models: true do
+describe GemnasiumService do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -31,7 +31,7 @@ describe GemnasiumService, models: true do
let(:project) { create(:project, :repository) }
before do
- @gemnasium_service = GemnasiumService.new
+ @gemnasium_service = described_class.new
allow(@gemnasium_service).to receive_messages(
project_id: project.id,
project: project,
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index dcb70ee28a8..d19dab8fd39 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GitlabIssueTrackerService, models: true do
+describe GitlabIssueTrackerService do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -23,38 +23,29 @@ describe GitlabIssueTrackerService, models: true do
describe 'project and issue urls' do
let(:project) { create(:empty_project) }
+ let(:service) { project.create_gitlab_issue_tracker_service(active: true) }
context 'with absolute urls' do
before do
- GitlabIssueTrackerService.default_url_options[:script_name] = "/gitlab/root"
- @service = project.create_gitlab_issue_tracker_service(active: true)
- end
-
- after do
- @service.destroy!
+ allow(described_class).to receive(:default_url_options).and_return(script_name: "/gitlab/root")
end
it 'gives the correct path' do
- expect(@service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues")
- expect(@service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new")
- expect(@service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432")
+ expect(service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues")
+ expect(service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new")
+ expect(service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432")
end
end
context 'with relative urls' do
before do
- GitlabIssueTrackerService.default_url_options[:script_name] = "/gitlab/root"
- @service = project.create_gitlab_issue_tracker_service(active: true)
- end
-
- after do
- @service.destroy!
+ allow(described_class).to receive(:default_url_options).and_return(script_name: "/gitlab/root")
end
it 'gives the correct path' do
- expect(@service.project_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
- expect(@service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
- expect(@service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
+ expect(service.issue_tracker_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
+ expect(service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
+ expect(service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
end
end
end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index c7c8e9651ab..7614bb897e8 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe HipchatService, models: true do
+describe HipchatService do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -25,7 +25,7 @@ describe HipchatService, models: true do
end
describe "Execute" do
- let(:hipchat) { HipchatService.new }
+ let(:hipchat) { described_class.new }
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' }
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index a5c4938b54e..cb9ca76fc3f 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
require 'socket'
require 'json'
-describe IrkerService, models: true do
+describe IrkerService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -27,7 +27,7 @@ describe IrkerService, models: true do
end
describe 'Execute' do
- let(:irker) { IrkerService.new }
+ let(:irker) { described_class.new }
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:sample_data) do
diff --git a/spec/models/project_services/issue_tracker_service_spec.rb b/spec/models/project_services/issue_tracker_service_spec.rb
index 869b25b933b..e6a1752576b 100644
--- a/spec/models/project_services/issue_tracker_service_spec.rb
+++ b/spec/models/project_services/issue_tracker_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe IssueTrackerService, models: true do
+describe IssueTrackerService do
describe 'Validations' do
let(:project) { create :project }
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index e2b8226124f..8f34b44930e 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe JiraService, models: true do
- include Gitlab::Routing.url_helpers
+describe JiraService do
+ include Gitlab::Routing
describe "Associations" do
it { is_expected.to belong_to :project }
@@ -15,7 +15,6 @@ describe JiraService, models: true do
end
it { is_expected.to validate_presence_of(:url) }
- it { is_expected.to validate_presence_of(:project_key) }
it_behaves_like 'issue tracker service URL attribute', :url
end
@@ -34,7 +33,6 @@ describe JiraService, models: true do
active: true,
username: 'username',
password: 'test',
- project_key: 'TEST',
jira_issue_transition_id: 24,
url: 'http://jira.test.com'
)
@@ -64,12 +62,12 @@ describe JiraService, models: true do
end
end
- describe '#reference_pattern' do
+ describe '.reference_pattern' do
it_behaves_like 'allows project key on reference pattern'
it 'does not allow # on the code' do
- expect(subject.reference_pattern.match('#123')).to be_nil
- expect(subject.reference_pattern.match('1#23#12')).to be_nil
+ expect(described_class.reference_pattern.match('#123')).to be_nil
+ expect(described_class.reference_pattern.match('1#23#12')).to be_nil
end
end
@@ -80,7 +78,7 @@ describe JiraService, models: true do
let(:merge_request) { create(:merge_request) }
before do
- @jira_service = JiraService.new
+ @jira_service = described_class.new
allow(@jira_service).to receive_messages(
project_id: project.id,
project: project,
@@ -88,7 +86,6 @@ describe JiraService, models: true do
url: 'http://jira.example.com',
username: 'gitlab_jira_username',
password: 'gitlab_jira_password',
- project_key: 'GitLabProject',
jira_issue_transition_id: "custom-id"
)
@@ -106,15 +103,15 @@ describe JiraService, models: true do
@jira_service.save
- project_issues_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123'
- @transitions_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/transitions'
- @comment_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/comment'
- @remote_link_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/remotelink'
+ project_issues_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123'
+ @transitions_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123/transitions'
+ @comment_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123/comment'
+ @remote_link_url = 'http://jira.example.com/rest/api/2/issue/JIRA-123/remotelink'
- WebMock.stub_request(:get, project_issues_url)
- WebMock.stub_request(:post, @transitions_url)
- WebMock.stub_request(:post, @comment_url)
- WebMock.stub_request(:post, @remote_link_url)
+ WebMock.stub_request(:get, project_issues_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password))
+ WebMock.stub_request(:post, @transitions_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password))
+ WebMock.stub_request(:post, @comment_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password))
+ WebMock.stub_request(:post, @remote_link_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password))
end
it "calls JIRA API" do
@@ -170,7 +167,7 @@ describe JiraService, models: true do
stub_config_setting(relative_url_root: '/gitlab')
stub_config_setting(url: Settings.send(:build_gitlab_url))
- allow(JiraService).to receive(:default_url_options) do
+ allow(described_class).to receive(:default_url_options) do
{ script_name: '/gitlab' }
end
@@ -196,26 +193,42 @@ describe JiraService, models: true do
project: create(:project),
url: 'http://jira.example.com',
username: 'jira_username',
- password: 'jira_password',
- project_key: 'GitLabProject'
+ password: 'jira_password'
)
end
- def test_settings(api_url)
- project_url = "http://jira_username:jira_password@#{api_url}/rest/api/2/project/GitLabProject"
+ def test_settings(api_url = nil)
+ api_url ||= 'jira.example.com'
+ test_url = "http://#{api_url}/rest/api/2/serverInfo"
- WebMock.stub_request(:get, project_url)
+ WebMock.stub_request(:get, test_url).with(basic_auth: %w(jira_username jira_password)).to_return(body: { url: 'http://url' }.to_json )
- jira_service.test_settings
+ jira_service.test(nil)
end
- it 'tries to get JIRA project with URL when API URL not set' do
- test_settings('jira.example.com')
+ context 'when the test succeeds' do
+ it 'tries to get JIRA project with URL when API URL not set' do
+ test_settings('jira.example.com')
+ end
+
+ it 'returns correct result' do
+ expect(test_settings).to eq( { success: true, result: { 'url' => 'http://url' } })
+ end
+
+ it 'tries to get JIRA project with API URL if set' do
+ jira_service.update(api_url: 'http://jira.api.com')
+ test_settings('jira.api.com')
+ end
end
- it 'tries to get JIRA project with API URL if set' do
- jira_service.update(api_url: 'http://jira.api.com')
- test_settings('jira.api.com')
+ context 'when the test fails' do
+ it 'returns result with the error' do
+ test_url = 'http://jira.example.com/rest/api/2/serverInfo'
+ WebMock.stub_request(:get, test_url).with(basic_auth: %w(jira_username jira_password))
+ .to_raise(JIRA::HTTPError.new(double(message: 'Some specific failure.')))
+
+ expect(jira_service.test(nil)).to eq( { success: false, result: 'Some specific failure.' })
+ end
end
end
@@ -224,7 +237,7 @@ describe JiraService, models: true do
context "when a password was previously set" do
before do
- @jira_service = JiraService.create!(
+ @jira_service = described_class.create!(
project: project,
properties: {
url: 'http://jira.example.com/web',
@@ -305,7 +318,7 @@ describe JiraService, models: true do
context 'when no password was previously set' do
before do
- @jira_service = JiraService.create(
+ @jira_service = described_class.create(
project: project,
properties: {
url: 'http://jira.example.com/rest/api/2',
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 858ad595dbf..55b96a0c12e 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe KubernetesService, models: true, caching: true do
+describe KubernetesService, :use_clean_rails_memory_store_caching do
include KubernetesHelpers
include ReactiveCachingHelpers
@@ -129,7 +129,7 @@ describe KubernetesService, models: true, caching: true do
it "returns the default namespace" do
is_expected.to eq(service.send(:default_namespace))
end
-
+
context 'when namespace is specified' do
before do
service.namespace = 'my-namespace'
@@ -201,6 +201,22 @@ describe KubernetesService, models: true, caching: true do
end
describe '#predefined_variables' do
+ let(:kubeconfig) do
+ config =
+ YAML.load(File.read(expand_fixture_path('config/kubeconfig.yml')))
+
+ config.dig('users', 0, 'user')['token'] =
+ 'token'
+
+ config.dig('clusters', 0, 'cluster')['certificate-authority-data'] =
+ Base64.encode64('CA PEM DATA')
+
+ config.dig('contexts', 0, 'context')['namespace'] =
+ namespace
+
+ YAML.dump(config)
+ end
+
before do
subject.api_url = 'https://kube.domain.com'
subject.token = 'token'
@@ -208,32 +224,34 @@ describe KubernetesService, models: true, caching: true do
subject.project = project
end
- context 'namespace is provided' do
- before do
- subject.namespace = 'my-project'
- end
-
+ shared_examples 'setting variables' do
it 'sets the variables' do
expect(subject.predefined_variables).to include(
{ key: 'KUBE_URL', value: 'https://kube.domain.com', public: true },
{ key: 'KUBE_TOKEN', value: 'token', public: false },
- { key: 'KUBE_NAMESPACE', value: 'my-project', public: true },
+ { key: 'KUBE_NAMESPACE', value: namespace, public: true },
+ { key: 'KUBECONFIG', value: kubeconfig, public: false, file: true },
{ key: 'KUBE_CA_PEM', value: 'CA PEM DATA', public: true },
{ key: 'KUBE_CA_PEM_FILE', value: 'CA PEM DATA', public: true, file: true }
)
end
end
- context 'no namespace provided' do
- it 'sets the variables' do
- expect(subject.predefined_variables).to include(
- { key: 'KUBE_URL', value: 'https://kube.domain.com', public: true },
- { key: 'KUBE_TOKEN', value: 'token', public: false },
- { key: 'KUBE_CA_PEM', value: 'CA PEM DATA', public: true },
- { key: 'KUBE_CA_PEM_FILE', value: 'CA PEM DATA', public: true, file: true }
- )
+ context 'namespace is provided' do
+ let(:namespace) { 'my-project' }
+
+ before do
+ subject.namespace = namespace
end
+ it_behaves_like 'setting variables'
+ end
+
+ context 'no namespace provided' do
+ let(:namespace) { subject.actual_namespace }
+
+ it_behaves_like 'setting variables'
+
it 'sets the KUBE_NAMESPACE' do
kube_namespace = subject.predefined_variables.find { |h| h[:key] == 'KUBE_NAMESPACE' }
diff --git a/spec/models/project_services/mattermost_service_spec.rb b/spec/models/project_services/mattermost_service_spec.rb
index 490d6aedffc..10c62ca55a7 100644
--- a/spec/models/project_services/mattermost_service_spec.rb
+++ b/spec/models/project_services/mattermost_service_spec.rb
@@ -1,5 +1,5 @@
require 'spec_helper'
-describe MattermostService, models: true do
+describe MattermostService do
it_behaves_like "slack or mattermost notifications"
end
diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
index fa38d23e82f..4c21c8b88bd 100644
--- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb
+++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MattermostSlashCommandsService, :models do
+describe MattermostSlashCommandsService do
it_behaves_like "chat slash commands service"
context 'Mattermost API' do
diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb
index bd50a2d1470..f89be20ad78 100644
--- a/spec/models/project_services/microsoft_teams_service_spec.rb
+++ b/spec/models/project_services/microsoft_teams_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MicrosoftTeamsService, models: true do
+describe MicrosoftTeamsService do
let(:chat_service) { described_class.new }
let(:webhook_url) { 'https://example.gitlab.com/' }
@@ -112,7 +112,7 @@ describe MicrosoftTeamsService, models: true do
let(:wiki_page_sample_data) do
service = WikiPages::CreateService.new(project, user, opts)
wiki_page = service.execute
- service.hook_data(wiki_page, 'create')
+ Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create')
end
it "calls Microsoft Teams API" do
diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb
index f4c1a9c94b6..f7d2372eca2 100644
--- a/spec/models/project_services/pivotaltracker_service_spec.rb
+++ b/spec/models/project_services/pivotaltracker_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe PivotaltrackerService, models: true do
+describe PivotaltrackerService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -26,7 +26,7 @@ describe PivotaltrackerService, models: true do
describe 'Execute' do
let(:service) do
- PivotaltrackerService.new.tap do |service|
+ described_class.new.tap do |service|
service.token = 'secret_api_token'
end
end
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index 71b53732164..bf39e8d7a39 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe PrometheusService, models: true, caching: true do
+describe PrometheusService, :use_clean_rails_memory_store_caching do
include PrometheusHelpers
include ReactiveCachingHelpers
@@ -65,13 +65,13 @@ describe PrometheusService, models: true, caching: true do
end
it 'returns reactive data' do
- is_expected.to eq(prometheus_data)
+ is_expected.to eq(prometheus_metrics_data)
end
end
end
describe '#deployment_metrics' do
- let(:deployment) { build_stubbed(:deployment)}
+ let(:deployment) { build_stubbed(:deployment) }
let(:deployment_query) { Gitlab::Prometheus::Queries::DeploymentQuery }
around do |example|
@@ -80,13 +80,16 @@ describe PrometheusService, models: true, caching: true do
context 'with valid data' do
subject { service.deployment_metrics(deployment) }
+ let(:fake_deployment_time) { 10 }
before do
stub_reactive_cache(service, prometheus_data, deployment_query, deployment.id)
end
it 'returns reactive data' do
- is_expected.to eq(prometheus_data.merge(deployment_time: deployment.created_at.to_i))
+ expect(deployment).to receive(:created_at).and_return(fake_deployment_time)
+
+ expect(subject).to eq(prometheus_metrics_data.merge(deployment_time: fake_deployment_time))
end
end
end
@@ -116,6 +119,7 @@ describe PrometheusService, models: true, caching: true do
end
it { expect(subject.to_json).to eq(prometheus_data.to_json) }
+ it { expect(subject.to_json).to eq(prometheus_data.to_json) }
end
[404, 500].each do |status|
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index 9171d9604ee..54b8c658ff6 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe PushoverService, models: true do
+describe PushoverService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -29,7 +29,7 @@ describe PushoverService, models: true do
end
describe 'Execute' do
- let(:pushover) { PushoverService.new }
+ let(:pushover) { described_class.new }
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:sample_data) do
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index 6631d9040b1..2ac14eab5e1 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe RedmineService, models: true do
+describe RedmineService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -31,11 +31,11 @@ describe RedmineService, models: true do
end
end
- describe '#reference_pattern' do
+ describe '.reference_pattern' do
it_behaves_like 'allows project key on reference pattern'
it 'does allow # on the reference' do
- expect(subject.reference_pattern.match('#123')[:issue]).to eq('123')
+ expect(described_class.reference_pattern.match('#123')[:issue]).to eq('123')
end
end
end
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index 9a3ecc66d83..13cf4d1915e 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -1,5 +1,5 @@
require 'spec_helper'
-describe SlackService, models: true do
+describe SlackService do
it_behaves_like "slack or mattermost notifications"
end
diff --git a/spec/models/project_services/slack_slash_commands_service_spec.rb b/spec/models/project_services/slack_slash_commands_service_spec.rb
index 5766aa340e2..aea674c4f6b 100644
--- a/spec/models/project_services/slack_slash_commands_service_spec.rb
+++ b/spec/models/project_services/slack_slash_commands_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackSlashCommandsService, :models do
+describe SlackSlashCommandsService do
it_behaves_like "chat slash commands service"
describe '#trigger' do
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index 7349eb4149a..47fd0c79e0b 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe TeamcityService, models: true, caching: true do
+describe TeamcityService, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers
let(:teamcity_url) { 'http://gitlab.com/teamcity' }
@@ -205,10 +205,12 @@ describe TeamcityService, models: true, caching: true do
end
def stub_request(status: 200, body: nil, build_status: 'success')
- teamcity_full_url = 'http://mic:password@gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,number:123'
+ teamcity_full_url = 'http://gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,number:123'
+ auth = %w(mic password)
+
body ||= %Q({"build":{"status":"#{build_status}","id":"666"}})
- WebMock.stub_request(:get, teamcity_full_url).to_return(
+ WebMock.stub_request(:get, teamcity_full_url).with(basic_auth: auth).to_return(
status: status,
headers: { 'Content-Type' => 'application/json' },
body: body
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index 5fe4885eeb4..1b439bcfad1 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectSnippet, models: true do
+describe ProjectSnippet do
describe "Associations" do
it { is_expected.to belong_to(:project) }
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index d7fcadb895e..473b7a88d61 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1,56 +1,56 @@
require 'spec_helper'
-describe Project, models: true do
+describe Project do
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to have_many(:users) }
it { is_expected.to have_many(:services) }
- it { is_expected.to have_many(:events).dependent(:destroy) }
- it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
- it { is_expected.to have_many(:issues).dependent(:destroy) }
- it { is_expected.to have_many(:milestones).dependent(:destroy) }
- it { is_expected.to have_many(:project_members).dependent(:destroy) }
+ it { is_expected.to have_many(:events) }
+ it { is_expected.to have_many(:merge_requests) }
+ it { is_expected.to have_many(:issues) }
+ it { is_expected.to have_many(:milestones) }
+ it { is_expected.to have_many(:project_members).dependent(:delete_all) }
it { is_expected.to have_many(:users).through(:project_members) }
- it { is_expected.to have_many(:requesters).dependent(:destroy) }
- it { is_expected.to have_many(:notes).dependent(:destroy) }
- it { is_expected.to have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) }
- it { is_expected.to have_many(:deploy_keys_projects).dependent(:destroy) }
+ it { is_expected.to have_many(:requesters).dependent(:delete_all) }
+ it { is_expected.to have_many(:notes) }
+ it { is_expected.to have_many(:snippets).class_name('ProjectSnippet') }
+ it { is_expected.to have_many(:deploy_keys_projects) }
it { is_expected.to have_many(:deploy_keys) }
- it { is_expected.to have_many(:hooks).dependent(:destroy) }
- it { is_expected.to have_many(:protected_branches).dependent(:destroy) }
- it { is_expected.to have_one(:forked_project_link).dependent(:destroy) }
- it { is_expected.to have_one(:slack_service).dependent(:destroy) }
- it { is_expected.to have_one(:microsoft_teams_service).dependent(:destroy) }
- it { is_expected.to have_one(:mattermost_service).dependent(:destroy) }
- it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
- it { is_expected.to have_one(:asana_service).dependent(:destroy) }
- it { is_expected.to have_many(:boards).dependent(:destroy) }
- it { is_expected.to have_one(:campfire_service).dependent(:destroy) }
- it { is_expected.to have_one(:drone_ci_service).dependent(:destroy) }
- it { is_expected.to have_one(:emails_on_push_service).dependent(:destroy) }
- it { is_expected.to have_one(:pipelines_email_service).dependent(:destroy) }
- it { is_expected.to have_one(:irker_service).dependent(:destroy) }
- it { is_expected.to have_one(:pivotaltracker_service).dependent(:destroy) }
- it { is_expected.to have_one(:hipchat_service).dependent(:destroy) }
- it { is_expected.to have_one(:flowdock_service).dependent(:destroy) }
- it { is_expected.to have_one(:assembla_service).dependent(:destroy) }
- it { is_expected.to have_one(:slack_slash_commands_service).dependent(:destroy) }
- it { is_expected.to have_one(:mattermost_slash_commands_service).dependent(:destroy) }
- it { is_expected.to have_one(:gemnasium_service).dependent(:destroy) }
- it { is_expected.to have_one(:buildkite_service).dependent(:destroy) }
- it { is_expected.to have_one(:bamboo_service).dependent(:destroy) }
- it { is_expected.to have_one(:teamcity_service).dependent(:destroy) }
- it { is_expected.to have_one(:jira_service).dependent(:destroy) }
- it { is_expected.to have_one(:redmine_service).dependent(:destroy) }
- it { is_expected.to have_one(:custom_issue_tracker_service).dependent(:destroy) }
- it { is_expected.to have_one(:bugzilla_service).dependent(:destroy) }
- it { is_expected.to have_one(:gitlab_issue_tracker_service).dependent(:destroy) }
- it { is_expected.to have_one(:external_wiki_service).dependent(:destroy) }
- it { is_expected.to have_one(:project_feature).dependent(:destroy) }
- it { is_expected.to have_one(:statistics).class_name('ProjectStatistics').dependent(:delete) }
- it { is_expected.to have_one(:import_data).class_name('ProjectImportData').dependent(:delete) }
+ it { is_expected.to have_many(:hooks) }
+ it { is_expected.to have_many(:protected_branches) }
+ it { is_expected.to have_one(:forked_project_link) }
+ it { is_expected.to have_one(:slack_service) }
+ it { is_expected.to have_one(:microsoft_teams_service) }
+ it { is_expected.to have_one(:mattermost_service) }
+ it { is_expected.to have_one(:pushover_service) }
+ it { is_expected.to have_one(:asana_service) }
+ it { is_expected.to have_many(:boards) }
+ it { is_expected.to have_one(:campfire_service) }
+ it { is_expected.to have_one(:drone_ci_service) }
+ it { is_expected.to have_one(:emails_on_push_service) }
+ it { is_expected.to have_one(:pipelines_email_service) }
+ it { is_expected.to have_one(:irker_service) }
+ it { is_expected.to have_one(:pivotaltracker_service) }
+ it { is_expected.to have_one(:hipchat_service) }
+ it { is_expected.to have_one(:flowdock_service) }
+ it { is_expected.to have_one(:assembla_service) }
+ it { is_expected.to have_one(:slack_slash_commands_service) }
+ it { is_expected.to have_one(:mattermost_slash_commands_service) }
+ it { is_expected.to have_one(:gemnasium_service) }
+ it { is_expected.to have_one(:buildkite_service) }
+ it { is_expected.to have_one(:bamboo_service) }
+ it { is_expected.to have_one(:teamcity_service) }
+ it { is_expected.to have_one(:jira_service) }
+ it { is_expected.to have_one(:redmine_service) }
+ it { is_expected.to have_one(:custom_issue_tracker_service) }
+ it { is_expected.to have_one(:bugzilla_service) }
+ it { is_expected.to have_one(:gitlab_issue_tracker_service) }
+ it { is_expected.to have_one(:external_wiki_service) }
+ it { is_expected.to have_one(:project_feature) }
+ it { is_expected.to have_one(:statistics).class_name('ProjectStatistics') }
+ it { is_expected.to have_one(:import_data).class_name('ProjectImportData') }
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:forked_project_link) }
it { is_expected.to have_many(:commit_statuses) }
@@ -62,22 +62,22 @@ describe Project, models: true do
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:pages_domains) }
- it { is_expected.to have_many(:labels).class_name('ProjectLabel').dependent(:destroy) }
- it { is_expected.to have_many(:users_star_projects).dependent(:destroy) }
- it { is_expected.to have_many(:environments).dependent(:destroy) }
- it { is_expected.to have_many(:deployments).dependent(:destroy) }
- it { is_expected.to have_many(:todos).dependent(:destroy) }
- it { is_expected.to have_many(:releases).dependent(:destroy) }
- it { is_expected.to have_many(:lfs_objects_projects).dependent(:destroy) }
- it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
- it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
+ it { is_expected.to have_many(:labels).class_name('ProjectLabel') }
+ it { is_expected.to have_many(:users_star_projects) }
+ it { is_expected.to have_many(:environments) }
+ it { is_expected.to have_many(:deployments) }
+ it { is_expected.to have_many(:todos) }
+ it { is_expected.to have_many(:releases) }
+ it { is_expected.to have_many(:lfs_objects_projects) }
+ it { is_expected.to have_many(:project_group_links) }
+ it { is_expected.to have_many(:notification_settings).dependent(:delete_all) }
it { is_expected.to have_many(:forks).through(:forked_project_links) }
it { is_expected.to have_many(:uploads).dependent(:destroy) }
- it { is_expected.to have_many(:pipeline_schedules).dependent(:destroy) }
+ it { is_expected.to have_many(:pipeline_schedules) }
context 'after initialized' do
it "has a project_feature" do
- expect(Project.new.project_feature).to be_present
+ expect(described_class.new.project_feature).to be_present
end
end
@@ -143,6 +143,10 @@ describe Project, models: true do
it { is_expected.to validate_length_of(:description).is_at_most(2000) }
+ it { is_expected.to validate_length_of(:ci_config_path).is_at_most(255) }
+ it { is_expected.to allow_value('').for(:ci_config_path) }
+ it { is_expected.not_to allow_value('test/../foo').for(:ci_config_path) }
+
it { is_expected.to validate_presence_of(:creator) }
it { is_expected.to validate_presence_of(:namespace) }
@@ -284,15 +288,6 @@ describe Project, models: true do
end
end
- describe 'default_scope' do
- it 'excludes projects pending deletion from the results' do
- project = create(:empty_project)
- create(:empty_project, pending_delete: true)
-
- expect(Project.all).to eq [project]
- end
- end
-
describe 'project token' do
it 'sets an random token if none provided' do
project = FactoryGirl.create :empty_project, runners_token: ''
@@ -314,10 +309,14 @@ describe Project, models: true do
end
describe 'delegation' do
- it { is_expected.to delegate_method(:add_guest).to(:team) }
- it { is_expected.to delegate_method(:add_reporter).to(:team) }
- it { is_expected.to delegate_method(:add_developer).to(:team) }
- it { is_expected.to delegate_method(:add_master).to(:team) }
+ [:add_guest, :add_reporter, :add_developer, :add_master, :add_user, :add_users].each do |method|
+ it { is_expected.to delegate_method(method).to(:team) }
+ end
+
+ it { is_expected.to delegate_method(:empty_repo?).to(:repository) }
+ it { is_expected.to delegate_method(:members).to(:team).with_prefix(true) }
+ it { is_expected.to delegate_method(:count).to(:forks).with_prefix(true) }
+ it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) }
end
describe '#to_reference' do
@@ -439,7 +438,7 @@ describe Project, models: true do
end
it 'returns valid url to repo' do
- project = Project.new(path: 'somewhere')
+ project = described_class.new(path: 'somewhere')
expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git')
end
@@ -534,15 +533,48 @@ describe Project, models: true do
end
context 'with external issues tracker' do
+ let!(:internal_issue) { create(:issue, project: project) }
before do
- allow(project).to receive(:default_issues_tracker?).and_return(false)
+ allow(project).to receive(:external_issue_tracker).and_return(true)
end
- it 'returns an ExternalIssue' do
- issue = project.get_issue('FOO-1234', user)
- expect(issue).to be_kind_of(ExternalIssue)
- expect(issue.iid).to eq 'FOO-1234'
- expect(issue.project).to eq project
+ context 'when internal issues are enabled' do
+ it 'returns interlan issue' do
+ issue = project.get_issue(internal_issue.iid, user)
+
+ expect(issue).to be_kind_of(Issue)
+ expect(issue.iid).to eq(internal_issue.iid)
+ expect(issue.project).to eq(project)
+ end
+
+ it 'returns an ExternalIssue when internal issue does not exists' do
+ issue = project.get_issue('FOO-1234', user)
+
+ expect(issue).to be_kind_of(ExternalIssue)
+ expect(issue.iid).to eq('FOO-1234')
+ expect(issue.project).to eq(project)
+ end
+ end
+
+ context 'when internal issues are disabled' do
+ before do
+ project.issues_enabled = false
+ project.save!
+ end
+
+ it 'returns always an External issues' do
+ issue = project.get_issue(internal_issue.iid, user)
+ expect(issue).to be_kind_of(ExternalIssue)
+ expect(issue.iid).to eq(internal_issue.iid.to_s)
+ expect(issue.project).to eq(project)
+ end
+
+ it 'returns an ExternalIssue when internal issue does not exists' do
+ issue = project.get_issue('FOO-1234', user)
+ expect(issue).to be_kind_of(ExternalIssue)
+ expect(issue.iid).to eq('FOO-1234')
+ expect(issue.project).to eq(project)
+ end
end
end
end
@@ -812,7 +844,7 @@ describe Project, models: true do
context 'when avatar file is uploaded' do
let(:project) { create(:empty_project, :with_avatar) }
- let(:avatar_path) { "/uploads/system/project/avatar/#{project.id}/dk.png" }
+ let(:avatar_path) { "/uploads/-/system/project/avatar/#{project.id}/dk.png" }
let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
it 'shows correct url' do
@@ -832,13 +864,13 @@ describe Project, models: true do
let(:avatar_path) { "/#{project.full_path}/avatar" }
- it { should eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" }
+ it { is_expected.to eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" }
end
context 'when git repo is empty' do
let(:project) { create(:empty_project) }
- it { should eq nil }
+ it { is_expected.to eq nil }
end
end
@@ -885,7 +917,7 @@ describe Project, models: true do
end
describe '.with_shared_runners' do
- subject { Project.with_shared_runners }
+ subject { described_class.with_shared_runners }
context 'when shared runners are enabled for project' do
let!(:project) { create(:empty_project, shared_runners_enabled: true) }
@@ -904,16 +936,16 @@ describe Project, models: true do
end
end
- describe '.cached_count', caching: true do
+ describe '.cached_count', :use_clean_rails_memory_store_caching do
let(:group) { create(:group, :public) }
let!(:project1) { create(:empty_project, :public, group: group) }
let!(:project2) { create(:empty_project, :public, group: group) }
it 'returns total project count' do
- expect(Project).to receive(:count).once.and_call_original
+ expect(described_class).to receive(:count).once.and_call_original
3.times do
- expect(Project.cached_count).to eq(2)
+ expect(described_class.cached_count).to eq(2)
end
end
end
@@ -958,7 +990,7 @@ describe Project, models: true do
user1.toggle_star(project1)
user2.toggle_star(project2)
- expect(Project.starred_by(user1)).to contain_exactly(project1)
+ expect(described_class.starred_by(user1)).to contain_exactly(project1)
end
end
@@ -1179,6 +1211,16 @@ describe Project, models: true do
expect(relation.search(project.namespace.name)).to eq([project])
end
+
+ describe 'with pending_delete project' do
+ let(:pending_delete_project) { create(:empty_project, pending_delete: true) }
+
+ it 'shows pending deletion project' do
+ search_result = described_class.search(pending_delete_project.name)
+
+ expect(search_result).to eq([pending_delete_project])
+ end
+ end
end
describe '#rename_repo' do
@@ -1215,6 +1257,8 @@ describe Project, models: true do
expect(project).to receive(:expire_caches_before_rename)
+ expect(project).to receive(:expires_full_path_cache)
+
project.rename_repo
end
@@ -1229,7 +1273,7 @@ describe Project, models: true do
subject { project.rename_repo }
- it { expect{subject}.to raise_error(Exception) }
+ it { expect{subject}.to raise_error(StandardError) }
end
end
@@ -1327,6 +1371,50 @@ describe Project, models: true do
end
end
+ describe '#ensure_repository' do
+ let(:project) { create(:project, :repository) }
+ let(:shell) { Gitlab::Shell.new }
+
+ before do
+ allow(project).to receive(:gitlab_shell).and_return(shell)
+ end
+
+ it 'creates the repository if it not exist' do
+ allow(project).to receive(:repository_exists?)
+ .and_return(false)
+
+ allow(shell).to receive(:add_repository)
+ .with(project.repository_storage_path, project.path_with_namespace)
+ .and_return(true)
+
+ expect(project).to receive(:create_repository).with(force: true)
+
+ project.ensure_repository
+ end
+
+ it 'does not create the repository if it exists' do
+ allow(project).to receive(:repository_exists?)
+ .and_return(true)
+
+ expect(project).not_to receive(:create_repository)
+
+ project.ensure_repository
+ end
+
+ it 'creates the repository if it is a fork' do
+ expect(project).to receive(:forked?).and_return(true)
+
+ allow(project).to receive(:repository_exists?)
+ .and_return(false)
+
+ expect(shell).to receive(:add_repository)
+ .with(project.repository_storage_path, project.path_with_namespace)
+ .and_return(true)
+
+ project.ensure_repository
+ end
+ end
+
describe '#user_can_push_to_empty_repo?' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -1457,6 +1545,28 @@ describe Project, models: true do
end
end
+ describe '#ci_config_path=' do
+ let(:project) { create(:empty_project) }
+
+ it 'sets nil' do
+ project.update!(ci_config_path: nil)
+
+ expect(project.ci_config_path).to be_nil
+ end
+
+ it 'sets a string' do
+ project.update!(ci_config_path: 'foo/.gitlab_ci.yml')
+
+ expect(project.ci_config_path).to eq('foo/.gitlab_ci.yml')
+ end
+
+ it 'sets a string but removes all leading slashes and null characters' do
+ project.update!(ci_config_path: "///f\0oo/\0/.gitlab_ci.yml")
+
+ expect(project.ci_config_path).to eq('foo//.gitlab_ci.yml')
+ end
+ end
+
describe 'Project import job' do
let(:project) { create(:empty_project, import_url: generate(:url)) }
@@ -1478,6 +1588,40 @@ describe Project, models: true do
end
end
+ describe 'project import state transitions' do
+ context 'state transition: [:started] => [:finished]' do
+ let(:housekeeping_service) { spy }
+
+ before do
+ allow(Projects::HousekeepingService).to receive(:new) { housekeeping_service }
+ end
+
+ it 'performs housekeeping when an import of a fresh project is completed' do
+ project = create(:project_empty_repo, :import_started, import_type: :github)
+
+ project.import_finish
+
+ expect(housekeeping_service).to have_received(:execute)
+ end
+
+ it 'does not perform housekeeping when project repository does not exist' do
+ project = create(:empty_project, :import_started, import_type: :github)
+
+ project.import_finish
+
+ expect(housekeeping_service).not_to have_received(:execute)
+ end
+
+ it 'does not perform housekeeping when project does not have a valid import type' do
+ project = create(:empty_project, :import_started, import_type: nil)
+
+ project.import_finish
+
+ expect(housekeeping_service).not_to have_received(:execute)
+ end
+ end
+ end
+
describe '#latest_successful_builds_for' do
def create_pipeline(status = 'success')
create(:ci_pipeline, project: project,
@@ -1768,7 +1912,12 @@ describe Project, models: true do
create(:ci_variable, :protected, value: 'protected', project: project)
end
- subject { project.secret_variables_for('ref') }
+ subject { project.secret_variables_for(ref: 'ref') }
+
+ before do
+ stub_application_setting(
+ default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ end
shared_examples 'ref is protected' do
it 'contains all the variables' do
@@ -1777,11 +1926,6 @@ describe Project, models: true do
end
context 'when the ref is not protected' do
- before do
- stub_application_setting(
- default_branch_protection: Gitlab::Access::PROTECTION_NONE)
- end
-
it 'contains only the secret variables' do
is_expected.to contain_exactly(secret_variable)
end
@@ -1868,7 +2012,7 @@ describe Project, models: true do
let!(:path) { project1.namespace.full_path }
it 'returns correct project' do
- expect(Project.inside_path(path)).to eq([project1])
+ expect(described_class.inside_path(path)).to eq([project1])
end
end
@@ -2072,7 +2216,7 @@ describe Project, models: true do
context 'with a user' do
let(:projects) do
- Project.all.public_or_visible_to_user(user)
+ described_class.all.public_or_visible_to_user(user)
end
it 'includes projects the user has access to' do
@@ -2086,10 +2230,27 @@ describe Project, models: true do
context 'without a user' do
it 'only includes public projects' do
- projects = Project.all.public_or_visible_to_user
+ projects = described_class.all.public_or_visible_to_user
expect(projects).to eq([public_project])
end
end
end
+
+ describe '#remove_private_deploy_keys' do
+ it 'removes the private deploy keys of a project' do
+ project = create(:empty_project)
+
+ private_key = create(:deploy_key, public: false)
+ public_key = create(:deploy_key, public: true)
+
+ create(:deploy_keys_project, deploy_key: private_key, project: project)
+ create(:deploy_keys_project, deploy_key: public_key, project: project)
+
+ project.remove_private_deploy_keys
+
+ expect(project.deploy_keys.where(public: false).any?).to eq(false)
+ expect(project.deploy_keys.where(public: true).any?).to eq(true)
+ end
+ end
end
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
index c5ffbda9821..be1b37730b1 100644
--- a/spec/models/project_statistics_spec.rb
+++ b/spec/models/project_statistics_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe ProjectStatistics, models: true do
+describe ProjectStatistics do
let(:project) { create :empty_project }
let(:statistics) { project.statistics }
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 49f2f8c0ad1..68228a038a8 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe ProjectTeam, models: true do
+describe ProjectTeam do
let(:master) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index bf74ac5ea25..c6ceb092810 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -1,11 +1,11 @@
require "spec_helper"
-describe ProjectWiki, models: true do
+describe ProjectWiki do
let(:project) { create(:empty_project) }
let(:repository) { project.repository }
let(:user) { project.owner }
let(:gitlab_shell) { Gitlab::Shell.new }
- let(:project_wiki) { ProjectWiki.new(project, user) }
+ let(:project_wiki) { described_class.new(project, user) }
subject { project_wiki }
@@ -278,6 +278,24 @@ describe ProjectWiki, models: true do
end
end
+ describe '#ensure_repository' do
+ it 'creates the repository if it not exist' do
+ allow(subject).to receive(:repository_exists?).and_return(false)
+
+ expect(subject).to receive(:create_repo!)
+
+ subject.ensure_repository
+ end
+
+ it 'does not create the repository if it exists' do
+ allow(subject).to receive(:repository_exists?).and_return(true)
+
+ expect(subject).not_to receive(:create_repo!)
+
+ subject.ensure_repository
+ end
+ end
+
describe '#hook_attrs' do
it 'returns a hash with values' do
expect(subject.hook_attrs).to be_a Hash
diff --git a/spec/models/protectable_dropdown_spec.rb b/spec/models/protectable_dropdown_spec.rb
index 4c9bade592b..5c5dcd9f5c9 100644
--- a/spec/models/protectable_dropdown_spec.rb
+++ b/spec/models/protectable_dropdown_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectableDropdown, models: true do
+describe ProtectableDropdown do
let(:project) { create(:project, :repository) }
let(:subject) { described_class.new(project, :branches) }
diff --git a/spec/models/protected_branch/merge_access_level_spec.rb b/spec/models/protected_branch/merge_access_level_spec.rb
index 1e7242e9fa8..f70503eadbc 100644
--- a/spec/models/protected_branch/merge_access_level_spec.rb
+++ b/spec/models/protected_branch/merge_access_level_spec.rb
@@ -1,5 +1,5 @@
require 'spec_helper'
-describe ProtectedBranch::MergeAccessLevel, :models do
+describe ProtectedBranch::MergeAccessLevel do
it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MASTER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) }
end
diff --git a/spec/models/protected_branch/push_access_level_spec.rb b/spec/models/protected_branch/push_access_level_spec.rb
index de68351198c..f161f345761 100644
--- a/spec/models/protected_branch/push_access_level_spec.rb
+++ b/spec/models/protected_branch/push_access_level_spec.rb
@@ -1,5 +1,5 @@
require 'spec_helper'
-describe ProtectedBranch::PushAccessLevel, :models do
+describe ProtectedBranch::PushAccessLevel do
it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MASTER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) }
end
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index ca347cf92c9..a54af3bfe59 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedBranch, models: true do
+describe ProtectedBranch do
subject { build_stubbed(:protected_branch) }
describe 'Associations' do
@@ -101,17 +101,17 @@ describe ProtectedBranch, models: true do
production = create(:protected_branch, name: "production")
staging = create(:protected_branch, name: "staging")
- expect(ProtectedBranch.matching("production")).to include(production)
- expect(ProtectedBranch.matching("production")).not_to include(staging)
+ expect(described_class.matching("production")).to include(production)
+ expect(described_class.matching("production")).not_to include(staging)
end
it "accepts a list of protected branches to search from, so as to avoid a DB call" do
production = build(:protected_branch, name: "production")
staging = build(:protected_branch, name: "staging")
- expect(ProtectedBranch.matching("production")).to be_empty
- expect(ProtectedBranch.matching("production", protected_refs: [production, staging])).to include(production)
- expect(ProtectedBranch.matching("production", protected_refs: [production, staging])).not_to include(staging)
+ expect(described_class.matching("production")).to be_empty
+ expect(described_class.matching("production", protected_refs: [production, staging])).to include(production)
+ expect(described_class.matching("production", protected_refs: [production, staging])).not_to include(staging)
end
end
@@ -120,17 +120,17 @@ describe ProtectedBranch, models: true do
production = create(:protected_branch, name: "production/*")
staging = create(:protected_branch, name: "staging/*")
- expect(ProtectedBranch.matching("production/some-branch")).to include(production)
- expect(ProtectedBranch.matching("production/some-branch")).not_to include(staging)
+ expect(described_class.matching("production/some-branch")).to include(production)
+ expect(described_class.matching("production/some-branch")).not_to include(staging)
end
it "accepts a list of protected branches to search from, so as to avoid a DB call" do
production = build(:protected_branch, name: "production/*")
staging = build(:protected_branch, name: "staging/*")
- expect(ProtectedBranch.matching("production/some-branch")).to be_empty
- expect(ProtectedBranch.matching("production/some-branch", protected_refs: [production, staging])).to include(production)
- expect(ProtectedBranch.matching("production/some-branch", protected_refs: [production, staging])).not_to include(staging)
+ expect(described_class.matching("production/some-branch")).to be_empty
+ expect(described_class.matching("production/some-branch", protected_refs: [production, staging])).to include(production)
+ expect(described_class.matching("production/some-branch", protected_refs: [production, staging])).not_to include(staging)
end
end
end
@@ -142,23 +142,23 @@ describe ProtectedBranch, models: true do
it 'returns true when the branch matches a protected branch via direct match' do
create(:protected_branch, project: project, name: "foo")
- expect(ProtectedBranch.protected?(project, 'foo')).to eq(true)
+ expect(described_class.protected?(project, 'foo')).to eq(true)
end
it 'returns true when the branch matches a protected branch via wildcard match' do
create(:protected_branch, project: project, name: "production/*")
- expect(ProtectedBranch.protected?(project, 'production/some-branch')).to eq(true)
+ expect(described_class.protected?(project, 'production/some-branch')).to eq(true)
end
it 'returns false when the branch does not match a protected branch via direct match' do
- expect(ProtectedBranch.protected?(project, 'foo')).to eq(false)
+ expect(described_class.protected?(project, 'foo')).to eq(false)
end
it 'returns false when the branch does not match a protected branch via wildcard match' do
create(:protected_branch, project: project, name: "production/*")
- expect(ProtectedBranch.protected?(project, 'staging/some-branch')).to eq(false)
+ expect(described_class.protected?(project, 'staging/some-branch')).to eq(false)
end
end
@@ -168,25 +168,25 @@ describe ProtectedBranch, models: true do
it 'returns false when default_protected_branch is unprotected' do
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
- expect(ProtectedBranch.protected?(project, 'master')).to be false
+ expect(described_class.protected?(project, 'master')).to be false
end
it 'returns false when default_protected_branch lets developers push' do
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
- expect(ProtectedBranch.protected?(project, 'master')).to be false
+ expect(described_class.protected?(project, 'master')).to be false
end
it 'returns true when default_branch_protection does not let developers push but let developer merge branches' do
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
- expect(ProtectedBranch.protected?(project, 'master')).to be true
+ expect(described_class.protected?(project, 'master')).to be true
end
it 'returns true when default_branch_protection is in full protection' do
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
- expect(ProtectedBranch.protected?(project, 'master')).to be true
+ expect(described_class.protected?(project, 'master')).to be true
end
end
end
diff --git a/spec/models/protected_tag_spec.rb b/spec/models/protected_tag_spec.rb
index 51353852a93..e5a0f6ec23f 100644
--- a/spec/models/protected_tag_spec.rb
+++ b/spec/models/protected_tag_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedTag, models: true do
+describe ProtectedTag do
describe 'Associations' do
it { is_expected.to belong_to(:project) }
end
diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb
index 71827421dd7..80943877095 100644
--- a/spec/models/redirect_route_spec.rb
+++ b/spec/models/redirect_route_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe RedirectRoute, models: true do
+describe RedirectRoute do
let(:group) { create(:group) }
let!(:redirect_route) { group.redirect_routes.create(path: 'gitlabb') }
@@ -11,7 +11,7 @@ describe RedirectRoute, models: true do
describe 'validations' do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
- it { is_expected.to validate_uniqueness_of(:path) }
+ it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
end
describe '.matching_path_and_descendants' do
@@ -21,7 +21,7 @@ describe RedirectRoute, models: true do
let!(:redirect5) { group.redirect_routes.create(path: 'gitlabb/test/baz') }
it 'returns correct routes' do
- expect(RedirectRoute.matching_path_and_descendants('gitlabb/test')).to match_array([redirect2, redirect3, redirect4, redirect5])
+ expect(described_class.matching_path_and_descendants('gitlabb/test')).to match_array([redirect2, redirect3, redirect4, redirect5])
end
end
end
diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb
index 527005b2b69..3f86347c3ae 100644
--- a/spec/models/release_spec.rb
+++ b/spec/models/release_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-RSpec.describe Release, type: :model do
+RSpec.describe Release do
let(:release) { create(:release) }
it { expect(release).to be_valid }
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 3e984ec7588..07ed66e127a 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Repository, models: true do
+describe Repository do
include RepoHelpers
TestBlob = Struct.new(:path)
@@ -347,6 +347,17 @@ describe Repository, models: true do
expect(blob.data).to eq('Changelog!')
end
+ it 'creates new file and dir when file_path has a forward slash' do
+ expect do
+ repository.create_file(user, 'new_dir/new_file.txt', 'File!',
+ message: 'Create new_file with new_dir',
+ branch_name: 'master')
+ end.to change { repository.commits('master').count }.by(1)
+
+ expect(repository.tree('master', 'new_dir').path).to eq('new_dir')
+ expect(repository.blob_at('master', 'new_dir/new_file.txt').data).to eq('File!')
+ end
+
it 'respects the autocrlf setting' do
repository.create_file(user, 'hello.txt', "Hello,\r\nWorld",
message: 'Add hello world',
@@ -550,7 +561,7 @@ describe Repository, models: true do
end
end
- describe "#changelog", caching: true do
+ describe "#changelog", :use_clean_rails_memory_store_caching do
it 'accepts changelog' do
expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('changelog')])
@@ -582,7 +593,7 @@ describe Repository, models: true do
end
end
- describe "#license_blob", caching: true do
+ describe "#license_blob", :use_clean_rails_memory_store_caching do
before do
repository.delete_file(
user, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master')
@@ -627,7 +638,7 @@ describe Repository, models: true do
end
end
- describe '#license_key', caching: true do
+ describe '#license_key', :use_clean_rails_memory_store_caching do
before do
repository.delete_file(user, 'LICENSE',
message: 'Remove LICENSE', branch_name: 'master')
@@ -692,7 +703,7 @@ describe Repository, models: true do
end
end
- describe "#gitlab_ci_yml", caching: true do
+ describe "#gitlab_ci_yml", :use_clean_rails_memory_store_caching do
it 'returns valid file' do
files = [TestBlob.new('file'), TestBlob.new('.gitlab-ci.yml'), TestBlob.new('copying')]
expect(repository.tree).to receive(:blobs).and_return(files)
@@ -780,7 +791,7 @@ describe Repository, models: true do
context 'when pre hooks were successful' do
it 'runs without errors' do
expect_any_instance_of(GitHooksService).to receive(:execute)
- .with(user, project.repository.path_to_repo, old_rev, blank_sha, 'refs/heads/feature')
+ .with(user, project, old_rev, blank_sha, 'refs/heads/feature')
expect { repository.rm_branch(user, 'feature') }.not_to raise_error
end
@@ -823,12 +834,7 @@ describe Repository, models: true do
service = GitHooksService.new
expect(GitHooksService).to receive(:new).and_return(service)
expect(service).to receive(:execute)
- .with(
- user,
- repository.path_to_repo,
- old_rev,
- new_rev,
- 'refs/heads/feature')
+ .with(user, project, old_rev, new_rev, 'refs/heads/feature')
.and_yield(service).and_return(true)
end
@@ -950,21 +956,25 @@ describe Repository, models: true do
end
end
- describe '#exists?' do
+ shared_examples 'repo exists check' do
it 'returns true when a repository exists' do
expect(repository.exists?).to eq(true)
end
- it 'returns false when a repository does not exist' do
- allow(repository).to receive(:refs_directory_exists?).and_return(false)
+ it 'returns false if no full path can be constructed' do
+ allow(repository).to receive(:path_with_namespace).and_return(nil)
expect(repository.exists?).to eq(false)
end
+ end
- it 'returns false when there is no namespace' do
- allow(repository).to receive(:path_with_namespace).and_return(nil)
+ describe '#exists?' do
+ context 'when repository_exists is disabled' do
+ it_behaves_like 'repo exists check'
+ end
- expect(repository.exists?).to eq(false)
+ context 'when repository_exists is enabled', skip_gitaly_mock: true do
+ it_behaves_like 'repo exists check'
end
end
@@ -1474,9 +1484,9 @@ describe Repository, models: true do
it 'passes commit SHA to pre-receive and update hooks,\
and tag SHA to post-receive hook' do
- pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', repository.path_to_repo)
- update_hook = Gitlab::Git::Hook.new('update', repository.path_to_repo)
- post_receive_hook = Gitlab::Git::Hook.new('post-receive', repository.path_to_repo)
+ pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', project)
+ update_hook = Gitlab::Git::Hook.new('update', project)
+ post_receive_hook = Gitlab::Git::Hook.new('post-receive', project)
allow(Gitlab::Git::Hook).to receive(:new)
.and_return(pre_receive_hook, update_hook, post_receive_hook)
@@ -1605,7 +1615,7 @@ describe Repository, models: true do
end
end
- describe '#contribution_guide', caching: true do
+ describe '#contribution_guide', :use_clean_rails_memory_store_caching do
it 'returns and caches the output' do
expect(repository).to receive(:file_on_head)
.with(:contributing)
@@ -1619,7 +1629,7 @@ describe Repository, models: true do
end
end
- describe '#gitignore', caching: true do
+ describe '#gitignore', :use_clean_rails_memory_store_caching do
it 'returns and caches the output' do
expect(repository).to receive(:file_on_head)
.with(:gitignore)
@@ -1632,7 +1642,7 @@ describe Repository, models: true do
end
end
- describe '#koding_yml', caching: true do
+ describe '#koding_yml', :use_clean_rails_memory_store_caching do
it 'returns and caches the output' do
expect(repository).to receive(:file_on_head)
.with(:koding)
@@ -1645,7 +1655,7 @@ describe Repository, models: true do
end
end
- describe '#readme', caching: true do
+ describe '#readme', :use_clean_rails_memory_store_caching do
context 'with a non-existing repository' do
it 'returns nil' do
allow(repository).to receive(:tree).with(:head).and_return(nil)
@@ -1816,7 +1826,7 @@ describe Repository, models: true do
end
end
- describe '#cache_method_output', caching: true do
+ describe '#cache_method_output', :use_clean_rails_memory_store_caching do
context 'with a non-existing repository' do
let(:value) do
repository.cache_method_output(:cats, fallback: 10) do
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index 1754253e0f2..bdacc60fb53 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Route, models: true do
+describe Route do
let(:group) { create(:group, path: 'git_lab', name: 'git_lab') }
let(:route) { group.route }
@@ -15,7 +15,7 @@ describe Route, models: true do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
- it { is_expected.to validate_uniqueness_of(:path) }
+ it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
end
describe 'callbacks' do
@@ -34,7 +34,7 @@ describe Route, models: true do
context 'after create' do
it 'calls #delete_conflicting_redirects' do
route.destroy
- new_route = Route.new(source: group, path: group.path)
+ new_route = described_class.new(source: group, path: group.path)
expect(new_route).to receive(:delete_conflicting_redirects)
new_route.save!
end
@@ -49,7 +49,7 @@ describe Route, models: true do
let!(:another_group_nested) { create(:group, path: 'another', name: 'another', parent: similar_group) }
it 'returns correct routes' do
- expect(Route.inside_path('git_lab')).to match_array([nested_group.route, deep_nested_group.route])
+ expect(described_class.inside_path('git_lab')).to match_array([nested_group.route, deep_nested_group.route])
end
end
diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb
index 5710edbc9e0..8b6b02916ae 100644
--- a/spec/models/sent_notification_spec.rb
+++ b/spec/models/sent_notification_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SentNotification, model: true do
+describe SentNotification do
describe 'validation' do
describe 'note validity' do
context "when the project doesn't match the noteable's project" do
@@ -38,7 +38,7 @@ describe SentNotification, model: true do
let(:issue) { create(:issue) }
it 'creates a new SentNotification' do
- expect { described_class.record(issue, user.id) }.to change { SentNotification.count }.by(1)
+ expect { described_class.record(issue, user.id) }.to change { described_class.count }.by(1)
end
end
@@ -47,7 +47,7 @@ describe SentNotification, model: true do
let(:note) { create(:diff_note_on_merge_request) }
it 'creates a new SentNotification' do
- expect { described_class.record_note(note, user.id) }.to change { SentNotification.count }.by(1)
+ expect { described_class.record_note(note, user.id) }.to change { described_class.count }.by(1)
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 134882648b9..dba9fc4ac9b 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Service, models: true do
+describe Service do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/snippet_blob_spec.rb b/spec/models/snippet_blob_spec.rb
index 120b390586b..7c71c458fcc 100644
--- a/spec/models/snippet_blob_spec.rb
+++ b/spec/models/snippet_blob_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SnippetBlob, models: true do
+describe SnippetBlob do
let(:snippet) { create(:snippet) }
subject { described_class.new(snippet) }
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 1e5c96fe593..904bf2c6144 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Snippet, models: true do
+describe Snippet do
describe 'modules' do
subject { described_class }
diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb
index 838fba6c92d..0d6b4384ada 100644
--- a/spec/models/spam_log_spec.rb
+++ b/spec/models/spam_log_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SpamLog, models: true do
+describe SpamLog do
let(:admin) { create(:admin) }
describe 'associations' do
diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb
index 9ab112bb2ee..9e4c2620d82 100644
--- a/spec/models/subscription_spec.rb
+++ b/spec/models/subscription_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Subscription, models: true do
+describe Subscription do
describe 'relationships' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:subscribable) }
diff --git a/spec/models/system_note_metadata_spec.rb b/spec/models/system_note_metadata_spec.rb
index d238e28209a..1e3f587e460 100644
--- a/spec/models/system_note_metadata_spec.rb
+++ b/spec/models/system_note_metadata_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SystemNoteMetadata, models: true do
+describe SystemNoteMetadata do
describe 'associations' do
it { is_expected.to belong_to(:note) }
end
diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb
index ebc694213b6..6e30798356c 100644
--- a/spec/models/timelog_spec.rb
+++ b/spec/models/timelog_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-RSpec.describe Timelog, type: :model do
+RSpec.describe Timelog do
subject { build(:timelog) }
let(:issue) { create(:issue) }
let(:merge_request) { create(:merge_request) }
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 3f80e1ac534..3e8f3848eca 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Todo, models: true do
+describe Todo do
let(:issue) { create(:issue) }
describe 'relationships' do
diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb
index a87983b7492..6bdb62a0864 100644
--- a/spec/models/tree_spec.rb
+++ b/spec/models/tree_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Tree, models: true do
+describe Tree do
let(:repository) { create(:project, :repository).repository }
let(:sha) { repository.root_ref }
diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb
index 2dea2c6015f..345382ea8c7 100644
--- a/spec/models/upload_spec.rb
+++ b/spec/models/upload_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe Upload, type: :model do
+describe Upload do
describe 'assocations' do
it { is_expected.to belong_to(:model) }
end
diff --git a/spec/models/user_agent_detail_spec.rb b/spec/models/user_agent_detail_spec.rb
index a8c25766e73..b4669f8c1c2 100644
--- a/spec/models/user_agent_detail_spec.rb
+++ b/spec/models/user_agent_detail_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe UserAgentDetail, type: :model do
+describe UserAgentDetail do
describe '.submittable?' do
it 'is submittable when not already submitted' do
detail = build(:user_agent_detail)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 314f8781867..ec98a3f3498 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe User, models: true do
+describe User do
include Gitlab::CurrentSettings
describe 'modules' do
@@ -114,7 +114,9 @@ describe User, models: true do
end
it 'validates uniqueness' do
- expect(subject).to validate_uniqueness_of(:username).case_insensitive
+ user = build(:user)
+
+ expect(user).to validate_uniqueness_of(:username).case_insensitive
end
end
@@ -259,7 +261,7 @@ describe User, models: true do
it "returns users with 2fa enabled via OTP" do
user_with_2fa = create(:user, :two_factor_via_otp)
user_without_2fa = create(:user)
- users_with_two_factor = User.with_two_factor.pluck(:id)
+ users_with_two_factor = described_class.with_two_factor.pluck(:id)
expect(users_with_two_factor).to include(user_with_2fa.id)
expect(users_with_two_factor).not_to include(user_without_2fa.id)
@@ -268,7 +270,7 @@ describe User, models: true do
it "returns users with 2fa enabled via U2F" do
user_with_2fa = create(:user, :two_factor_via_u2f)
user_without_2fa = create(:user)
- users_with_two_factor = User.with_two_factor.pluck(:id)
+ users_with_two_factor = described_class.with_two_factor.pluck(:id)
expect(users_with_two_factor).to include(user_with_2fa.id)
expect(users_with_two_factor).not_to include(user_without_2fa.id)
@@ -277,7 +279,7 @@ describe User, models: true do
it "returns users with 2fa enabled via OTP and U2F" do
user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f)
user_without_2fa = create(:user)
- users_with_two_factor = User.with_two_factor.pluck(:id)
+ users_with_two_factor = described_class.with_two_factor.pluck(:id)
expect(users_with_two_factor).to eq([user_with_2fa.id])
expect(users_with_two_factor).not_to include(user_without_2fa.id)
@@ -288,7 +290,7 @@ describe User, models: true do
it "excludes users with 2fa enabled via OTP" do
user_with_2fa = create(:user, :two_factor_via_otp)
user_without_2fa = create(:user)
- users_without_two_factor = User.without_two_factor.pluck(:id)
+ users_without_two_factor = described_class.without_two_factor.pluck(:id)
expect(users_without_two_factor).to include(user_without_2fa.id)
expect(users_without_two_factor).not_to include(user_with_2fa.id)
@@ -297,7 +299,7 @@ describe User, models: true do
it "excludes users with 2fa enabled via U2F" do
user_with_2fa = create(:user, :two_factor_via_u2f)
user_without_2fa = create(:user)
- users_without_two_factor = User.without_two_factor.pluck(:id)
+ users_without_two_factor = described_class.without_two_factor.pluck(:id)
expect(users_without_two_factor).to include(user_without_2fa.id)
expect(users_without_two_factor).not_to include(user_with_2fa.id)
@@ -306,7 +308,7 @@ describe User, models: true do
it "excludes users with 2fa enabled via OTP and U2F" do
user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f)
user_without_2fa = create(:user)
- users_without_two_factor = User.without_two_factor.pluck(:id)
+ users_without_two_factor = described_class.without_two_factor.pluck(:id)
expect(users_without_two_factor).to include(user_without_2fa.id)
expect(users_without_two_factor).not_to include(user_with_2fa.id)
@@ -322,8 +324,8 @@ describe User, models: true do
create(:todo, user: current_user, author: user_2, state: :done)
create(:todo, user: current_user, author: user_3, state: :pending)
- expect(User.todo_authors(current_user.id, 'pending')).to eq [user_3]
- expect(User.todo_authors(current_user.id, 'done')).to eq [user_2]
+ expect(described_class.todo_authors(current_user.id, 'pending')).to eq [user_3]
+ expect(described_class.todo_authors(current_user.id, 'done')).to eq [user_2]
end
end
end
@@ -348,7 +350,27 @@ describe User, models: true do
end
end
- describe '#update_tracked_fields!', :redis do
+ describe 'after update hook' do
+ describe '.update_invalid_gpg_signatures' do
+ let(:user) do
+ create(:user, email: 'tula.torphy@abshire.ca').tap do |user|
+ user.skip_reconfirmation!
+ end
+ end
+
+ it 'does nothing when the name is updated' do
+ expect(user).not_to receive(:update_invalid_gpg_signatures)
+ user.update_attributes!(name: 'Bette')
+ end
+
+ it 'synchronizes the gpg keys when the email is updated' do
+ expect(user).to receive(:update_invalid_gpg_signatures)
+ user.update_attributes!(email: 'shawnee.ritchie@denesik.com')
+ end
+ end
+ end
+
+ describe '#update_tracked_fields!', :clean_gitlab_redis_shared_state do
let(:request) { OpenStruct.new(remote_ip: "127.0.0.1") }
let(:user) { create(:user) }
@@ -607,39 +629,39 @@ describe User, models: true do
let(:user) { double }
it 'filters by active users by default' do
- expect(User).to receive(:active).and_return([user])
+ expect(described_class).to receive(:active).and_return([user])
- expect(User.filter(nil)).to include user
+ expect(described_class.filter(nil)).to include user
end
it 'filters by admins' do
- expect(User).to receive(:admins).and_return([user])
+ expect(described_class).to receive(:admins).and_return([user])
- expect(User.filter('admins')).to include user
+ expect(described_class.filter('admins')).to include user
end
it 'filters by blocked' do
- expect(User).to receive(:blocked).and_return([user])
+ expect(described_class).to receive(:blocked).and_return([user])
- expect(User.filter('blocked')).to include user
+ expect(described_class.filter('blocked')).to include user
end
it 'filters by two_factor_disabled' do
- expect(User).to receive(:without_two_factor).and_return([user])
+ expect(described_class).to receive(:without_two_factor).and_return([user])
- expect(User.filter('two_factor_disabled')).to include user
+ expect(described_class.filter('two_factor_disabled')).to include user
end
it 'filters by two_factor_enabled' do
- expect(User).to receive(:with_two_factor).and_return([user])
+ expect(described_class).to receive(:with_two_factor).and_return([user])
- expect(User.filter('two_factor_enabled')).to include user
+ expect(described_class.filter('two_factor_enabled')).to include user
end
it 'filters by wop' do
- expect(User).to receive(:without_projects).and_return([user])
+ expect(described_class).to receive(:without_projects).and_return([user])
- expect(User.filter('wop')).to include user
+ expect(described_class.filter('wop')).to include user
end
end
@@ -660,9 +682,9 @@ describe User, models: true do
project.request_access(user_without_project2)
end
- it { expect(User.without_projects).not_to include user }
- it { expect(User.without_projects).to include user_without_project }
- it { expect(User.without_projects).to include user_without_project2 }
+ it { expect(described_class.without_projects).not_to include user }
+ it { expect(described_class.without_projects).to include user_without_project }
+ it { expect(described_class.without_projects).to include user_without_project2 }
end
describe 'user creation' do
@@ -678,7 +700,7 @@ describe User, models: true do
end
describe 'with defaults' do
- let(:user) { User.new }
+ let(:user) { described_class.new }
it "applies defaults to user" do
expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit)
@@ -688,7 +710,7 @@ describe User, models: true do
end
describe 'with default overrides' do
- let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true) }
+ let(:user) { described_class.new(projects_limit: 123, can_create_group: false, can_create_team: true) }
it "applies defaults to user" do
expect(user.projects_limit).to eq(123)
@@ -738,58 +760,65 @@ describe User, models: true do
it 'finds by primary email' do
user = create(:user, email: 'foo@example.com')
- expect(User.find_by_any_email(user.email)).to eq user
+ expect(described_class.find_by_any_email(user.email)).to eq user
end
it 'finds by secondary email' do
email = create(:email, email: 'foo@example.com')
user = email.user
- expect(User.find_by_any_email(email.email)).to eq user
+ expect(described_class.find_by_any_email(email.email)).to eq user
end
it 'returns nil when nothing found' do
- expect(User.find_by_any_email('')).to be_nil
+ expect(described_class.find_by_any_email('')).to be_nil
end
end
describe '.search' do
- let(:user) { create(:user) }
+ let!(:user) { create(:user, name: 'user', username: 'usern', email: 'email@gmail.com') }
+ let!(:user2) { create(:user, name: 'user name', username: 'username', email: 'someemail@gmail.com') }
- it 'returns users with a matching name' do
- expect(described_class.search(user.name)).to eq([user])
- end
+ describe 'name matching' do
+ it 'returns users with a matching name with exact match first' do
+ expect(described_class.search(user.name)).to eq([user, user2])
+ end
- it 'returns users with a partially matching name' do
- expect(described_class.search(user.name[0..2])).to eq([user])
- end
+ it 'returns users with a partially matching name' do
+ expect(described_class.search(user.name[0..2])).to eq([user, user2])
+ end
- it 'returns users with a matching name regardless of the casing' do
- expect(described_class.search(user.name.upcase)).to eq([user])
+ it 'returns users with a matching name regardless of the casing' do
+ expect(described_class.search(user2.name.upcase)).to eq([user2])
+ end
end
- it 'returns users with a matching Email' do
- expect(described_class.search(user.email)).to eq([user])
- end
+ describe 'email matching' do
+ it 'returns users with a matching Email' do
+ expect(described_class.search(user.email)).to eq([user, user2])
+ end
- it 'returns users with a partially matching Email' do
- expect(described_class.search(user.email[0..2])).to eq([user])
- end
+ it 'returns users with a partially matching Email' do
+ expect(described_class.search(user.email[0..2])).to eq([user, user2])
+ end
- it 'returns users with a matching Email regardless of the casing' do
- expect(described_class.search(user.email.upcase)).to eq([user])
+ it 'returns users with a matching Email regardless of the casing' do
+ expect(described_class.search(user2.email.upcase)).to eq([user2])
+ end
end
- it 'returns users with a matching username' do
- expect(described_class.search(user.username)).to eq([user])
- end
+ describe 'username matching' do
+ it 'returns users with a matching username' do
+ expect(described_class.search(user.username)).to eq([user, user2])
+ end
- it 'returns users with a partially matching username' do
- expect(described_class.search(user.username[0..2])).to eq([user])
- end
+ it 'returns users with a partially matching username' do
+ expect(described_class.search(user.username[0..2])).to eq([user, user2])
+ end
- it 'returns users with a matching username regardless of the casing' do
- expect(described_class.search(user.username.upcase)).to eq([user])
+ it 'returns users with a matching username regardless of the casing' do
+ expect(described_class.search(user2.username.upcase)).to eq([user2])
+ end
end
end
@@ -890,12 +919,12 @@ describe User, models: true do
let!(:user) { create(:user, username: username) }
it 'gets the correct user' do
- expect(User.by_login(user.email.upcase)).to eq user
- expect(User.by_login(user.email)).to eq user
- expect(User.by_login(username.downcase)).to eq user
- expect(User.by_login(username)).to eq user
- expect(User.by_login(nil)).to be_nil
- expect(User.by_login('')).to be_nil
+ expect(described_class.by_login(user.email.upcase)).to eq user
+ expect(described_class.by_login(user.email)).to eq user
+ expect(described_class.by_login(username.downcase)).to eq user
+ expect(described_class.by_login(username)).to eq user
+ expect(described_class.by_login(nil)).to be_nil
+ expect(described_class.by_login('')).to be_nil
end
end
@@ -929,12 +958,12 @@ describe User, models: true do
let!(:route) { user.namespace.route }
it 'returns the user' do
- expect(User.find_by_full_path(route.path)).to eq(user)
+ expect(described_class.find_by_full_path(route.path)).to eq(user)
end
it 'is case-insensitive' do
- expect(User.find_by_full_path(route.path.upcase)).to eq(user)
- expect(User.find_by_full_path(route.path.downcase)).to eq(user)
+ expect(described_class.find_by_full_path(route.path.upcase)).to eq(user)
+ expect(described_class.find_by_full_path(route.path.downcase)).to eq(user)
end
end
@@ -943,18 +972,18 @@ describe User, models: true do
context 'without the follow_redirects option' do
it 'returns nil' do
- expect(User.find_by_full_path(redirect_route.path)).to eq(nil)
+ expect(described_class.find_by_full_path(redirect_route.path)).to eq(nil)
end
end
context 'with the follow_redirects option set to true' do
it 'returns the user' do
- expect(User.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user)
+ expect(described_class.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user)
end
it 'is case-insensitive' do
- expect(User.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user)
- expect(User.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user)
+ expect(described_class.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user)
+ expect(described_class.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user)
end
end
end
@@ -962,12 +991,12 @@ describe User, models: true do
context 'without a route or a redirect route matching the given path' do
context 'without the follow_redirects option' do
it 'returns nil' do
- expect(User.find_by_full_path('unknown')).to eq(nil)
+ expect(described_class.find_by_full_path('unknown')).to eq(nil)
end
end
context 'with the follow_redirects option set to true' do
it 'returns nil' do
- expect(User.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
+ expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil)
end
end
end
@@ -977,7 +1006,7 @@ describe User, models: true do
let!(:group) { create(:group, path: 'group_path', owner: user) }
it 'returns nil' do
- expect(User.find_by_full_path('group_path')).to eq(nil)
+ expect(described_class.find_by_full_path('group_path')).to eq(nil)
end
end
@@ -985,7 +1014,7 @@ describe User, models: true do
let!(:group) { create(:group, path: 'group_path') }
it 'returns nil' do
- expect(User.find_by_full_path('group_path')).to eq(nil)
+ expect(described_class.find_by_full_path('group_path')).to eq(nil)
end
end
end
@@ -1021,7 +1050,7 @@ describe User, models: true do
context 'when avatar file is uploaded' do
let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
- let(:avatar_path) { "/uploads/system/user/avatar/#{user.id}/dk.png" }
+ let(:avatar_path) { "/uploads/-/system/user/avatar/#{user.id}/dk.png" }
it 'shows correct avatar url' do
expect(user.avatar_url).to eq(avatar_path)
@@ -1035,7 +1064,7 @@ describe User, models: true do
end
describe '#requires_ldap_check?' do
- let(:user) { User.new }
+ let(:user) { described_class.new }
it 'is false when LDAP is disabled' do
# Create a condition which would otherwise cause 'true' to be returned
@@ -1152,6 +1181,18 @@ describe User, models: true do
end
end
+ describe '#sanitize_attrs' do
+ let(:user) { build(:user, name: 'test & user', skype: 'test&user') }
+
+ it 'encodes HTML entities in the Skype attribute' do
+ expect { user.sanitize_attrs }.to change { user.skype }.to('test&amp;user')
+ end
+
+ it 'does not encode HTML entities in the name attribute' do
+ expect { user.sanitize_attrs }.not_to change { user.name }
+ end
+ end
+
describe '#starred?' do
it 'determines if user starred a project' do
user = create :user
@@ -1194,7 +1235,7 @@ describe User, models: true do
describe '#sort' do
before do
- User.delete_all
+ described_class.delete_all
@user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha'
@user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
@user2 = create :user, created_at: Date.today - 2, last_sign_in_at: nil, name: 'Beta'
@@ -1202,34 +1243,34 @@ describe User, models: true do
context 'when sort by recent_sign_in' do
it 'sorts users by the recent sign-in time' do
- expect(User.sort('recent_sign_in').first).to eq(@user)
+ expect(described_class.sort('recent_sign_in').first).to eq(@user)
end
it 'pushes users who never signed in to the end' do
- expect(User.sort('recent_sign_in').third).to eq(@user2)
+ expect(described_class.sort('recent_sign_in').third).to eq(@user2)
end
end
context 'when sort by oldest_sign_in' do
it 'sorts users by the oldest sign-in time' do
- expect(User.sort('oldest_sign_in').first).to eq(@user1)
+ expect(described_class.sort('oldest_sign_in').first).to eq(@user1)
end
it 'pushes users who never signed in to the end' do
- expect(User.sort('oldest_sign_in').third).to eq(@user2)
+ expect(described_class.sort('oldest_sign_in').third).to eq(@user2)
end
end
it 'sorts users in descending order by their creation time' do
- expect(User.sort('created_desc').first).to eq(@user)
+ expect(described_class.sort('created_desc').first).to eq(@user)
end
it 'sorts users in ascending order by their creation time' do
- expect(User.sort('created_asc').first).to eq(@user2)
+ expect(described_class.sort('created_asc').first).to eq(@user2)
end
it 'sorts users by id in descending order when nil is passed' do
- expect(User.sort(nil).first).to eq(@user2)
+ expect(described_class.sort(nil).first).to eq(@user2)
end
end
@@ -1677,7 +1718,7 @@ describe User, models: true do
end
end
- describe '#refresh_authorized_projects', redis: true do
+ describe '#refresh_authorized_projects', clean_gitlab_redis_shared_state: true do
let(:project1) { create(:empty_project) }
let(:project2) { create(:empty_project) }
let(:user) { create(:user) }
@@ -1733,9 +1774,23 @@ describe User, models: true do
end
end
+ describe '#full_private_access?' do
+ it 'returns false for regular user' do
+ user = build(:user)
+
+ expect(user.full_private_access?).to be_falsy
+ end
+
+ it 'returns true for admin user' do
+ user = build(:user, :admin)
+
+ expect(user.full_private_access?).to be_truthy
+ end
+ end
+
describe '.ghost' do
it "creates a ghost user if one isn't already present" do
- ghost = User.ghost
+ ghost = described_class.ghost
expect(ghost).to be_ghost
expect(ghost).to be_persisted
@@ -1743,16 +1798,16 @@ describe User, models: true do
it "does not create a second ghost user if one is already present" do
expect do
- User.ghost
- User.ghost
- end.to change { User.count }.by(1)
- expect(User.ghost).to eq(User.ghost)
+ described_class.ghost
+ described_class.ghost
+ end.to change { described_class.count }.by(1)
+ expect(described_class.ghost).to eq(described_class.ghost)
end
context "when a regular user exists with the username 'ghost'" do
it "creates a ghost user with a non-conflicting username" do
create(:user, username: 'ghost')
- ghost = User.ghost
+ ghost = described_class.ghost
expect(ghost).to be_persisted
expect(ghost.username).to eq('ghost1')
@@ -1762,7 +1817,7 @@ describe User, models: true do
context "when a regular user exists with the email 'ghost@example.com'" do
it "creates a ghost user with a non-conflicting email" do
create(:user, email: 'ghost@example.com')
- ghost = User.ghost
+ ghost = described_class.ghost
expect(ghost).to be_persisted
expect(ghost.email).to eq('ghost1@example.com')
@@ -1775,7 +1830,7 @@ describe User, models: true do
end
it 'creates a ghost user' do
- expect(User.ghost).to be_persisted
+ expect(described_class.ghost).to be_persisted
end
end
end
@@ -1854,13 +1909,13 @@ describe User, models: true do
context '.active' do
before do
- User.ghost
+ described_class.ghost
create(:user, name: 'user', state: 'active')
create(:user, name: 'user', state: 'blocked')
end
it 'only counts active and non internal users' do
- expect(User.active.count).to eq(1)
+ expect(described_class.active.count).to eq(1)
end
end
@@ -1899,4 +1954,26 @@ describe User, models: true do
user.invalidate_merge_request_cache_counts
end
end
+
+ describe '#allow_password_authentication?' do
+ context 'regular user' do
+ let(:user) { build(:user) }
+
+ it 'returns true when sign-in is enabled' do
+ expect(user.allow_password_authentication?).to be_truthy
+ end
+
+ it 'returns false when sign-in is disabled' do
+ stub_application_setting(password_authentication_enabled: false)
+
+ expect(user.allow_password_authentication?).to be_falsey
+ end
+ end
+
+ it 'returns false for ldap user' do
+ user = create(:omniauth_user, provider: 'ldapmain')
+
+ expect(user.allow_password_authentication?).to be_falsey
+ end
+ end
end
diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb
index 1caaa557085..fb8575cfe2b 100644
--- a/spec/models/wiki_directory_spec.rb
+++ b/spec/models/wiki_directory_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-RSpec.describe WikiDirectory, models: true do
+RSpec.describe WikiDirectory do
describe 'validations' do
subject { build(:wiki_directory) }
@@ -10,7 +10,7 @@ RSpec.describe WikiDirectory, models: true do
describe '#initialize' do
context 'when there are pages' do
let(:pages) { [build(:wiki_page)] }
- let(:directory) { WikiDirectory.new('/path_up_to/dir', pages) }
+ let(:directory) { described_class.new('/path_up_to/dir', pages) }
it 'sets the slug attribute' do
expect(directory.slug).to eq('/path_up_to/dir')
@@ -22,7 +22,7 @@ RSpec.describe WikiDirectory, models: true do
end
context 'when there are no pages' do
- let(:directory) { WikiDirectory.new('/path_up_to/dir') }
+ let(:directory) { described_class.new('/path_up_to/dir') }
it 'sets the slug attribute' do
expect(directory.slug).to eq('/path_up_to/dir')
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index 4a73552b8a6..55d9c4ddd7b 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -1,17 +1,17 @@
require "spec_helper"
-describe WikiPage, models: true do
+describe WikiPage do
let(:project) { create(:empty_project) }
let(:user) { project.owner }
let(:wiki) { ProjectWiki.new(project, user) }
- subject { WikiPage.new(wiki) }
+ subject { described_class.new(wiki) }
describe '.group_by_directory' do
context 'when there are no pages' do
it 'returns an empty array' do
- expect(WikiPage.group_by_directory(nil)).to eq([])
- expect(WikiPage.group_by_directory([])).to eq([])
+ expect(described_class.group_by_directory(nil)).to eq([])
+ expect(described_class.group_by_directory([])).to eq([])
end
end
@@ -39,7 +39,7 @@ describe WikiPage, models: true do
it 'returns an array with pages and directories' do
expected_grouped_entries = [page_1, dir_1, dir_1_1, dir_2]
- grouped_entries = WikiPage.group_by_directory(wiki.pages)
+ grouped_entries = described_class.group_by_directory(wiki.pages)
grouped_entries.each_with_index do |page_or_dir, i|
expected_page_or_dir = expected_grouped_entries[i]
@@ -56,7 +56,7 @@ describe WikiPage, models: true do
expected_order = ['page_1', 'dir_1/page_2', 'dir_1/dir_1_1/page_3',
'dir_2/page_4', 'dir_2/page_5']
- grouped_entries = WikiPage.group_by_directory(wiki.pages)
+ grouped_entries = described_class.group_by_directory(wiki.pages)
actual_order =
grouped_entries.map do |page_or_dir|
@@ -72,7 +72,7 @@ describe WikiPage, models: true do
it 'removes hyphens from a name' do
name = 'a-name--with-hyphens'
- expect(WikiPage.unhyphenize(name)).to eq('a name with hyphens')
+ expect(described_class.unhyphenize(name)).to eq('a name with hyphens')
end
end
@@ -81,7 +81,7 @@ describe WikiPage, models: true do
before do
create_page("test page", "test content")
@page = wiki.wiki.paged("test page")
- @wiki_page = WikiPage.new(wiki, @page, true)
+ @wiki_page = described_class.new(wiki, @page, true)
end
it "sets the slug attribute" do
@@ -208,6 +208,18 @@ describe WikiPage, models: true do
expect(@page.update("more content")).to be_truthy
end
end
+
+ context 'with same last commit sha' do
+ it 'returns true' do
+ expect(@page.update('more content', last_commit_sha: @page.last_commit_sha)).to be_truthy
+ end
+ end
+
+ context 'with different last commit sha' do
+ it 'raises exception' do
+ expect { @page.update('more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError)
+ end
+ end
end
describe "#destroy" do
@@ -331,6 +343,30 @@ describe WikiPage, models: true do
end
end
+ describe '#last_commit_sha' do
+ before do
+ create_page("Update", "content")
+ @page = wiki.find_page("Update")
+ end
+
+ after do
+ destroy_page("Update")
+ end
+
+ it 'returns commit sha' do
+ expect(@page.last_commit_sha).to eq @page.commit.sha
+ end
+
+ it 'is changed after page updated' do
+ last_commit_sha_before_update = @page.last_commit_sha
+
+ @page.update("new content")
+ @page = wiki.find_page("Update")
+
+ expect(@page.last_commit_sha).not_to eq last_commit_sha_before_update
+ end
+ end
+
private
def remove_temp_repo(path)
diff --git a/spec/policies/base_policy_spec.rb b/spec/policies/base_policy_spec.rb
index 02acdcb36df..c03d95b34db 100644
--- a/spec/policies/base_policy_spec.rb
+++ b/spec/policies/base_policy_spec.rb
@@ -1,19 +1,19 @@
require 'spec_helper'
-describe BasePolicy, models: true do
+describe BasePolicy do
describe '.class_for' do
it 'detects policy class based on the subject ancestors' do
- expect(described_class.class_for(GenericCommitStatus.new)).to eq(CommitStatusPolicy)
+ expect(DeclarativePolicy.class_for(GenericCommitStatus.new)).to eq(CommitStatusPolicy)
end
it 'detects policy class for a presented subject' do
presentee = Ci::BuildPresenter.new(Ci::Build.new)
- expect(described_class.class_for(presentee)).to eq(Ci::BuildPolicy)
+ expect(DeclarativePolicy.class_for(presentee)).to eq(Ci::BuildPolicy)
end
it 'uses GlobalPolicy when :global is given' do
- expect(described_class.class_for(:global)).to eq(GlobalPolicy)
+ expect(DeclarativePolicy.class_for(:global)).to eq(GlobalPolicy)
end
end
end
diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb
index 48a139d4b83..a83a83a7349 100644
--- a/spec/policies/ci/build_policy_spec.rb
+++ b/spec/policies/ci/build_policy_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe Ci::BuildPolicy, :models do
+describe Ci::BuildPolicy do
let(:user) { create(:user) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
- let(:policies) do
- described_class.abilities(user, build).to_set
+ let(:policy) do
+ described_class.new(user, build)
end
shared_context 'public pipelines disabled' do
@@ -21,7 +21,7 @@ describe Ci::BuildPolicy, :models do
context 'when public builds are enabled' do
it 'does not include ability to read build' do
- expect(policies).not_to include :read_build
+ expect(policy).not_to be_allowed :read_build
end
end
@@ -29,7 +29,7 @@ describe Ci::BuildPolicy, :models do
include_context 'public pipelines disabled'
it 'does not include ability to read build' do
- expect(policies).not_to include :read_build
+ expect(policy).not_to be_allowed :read_build
end
end
end
@@ -39,7 +39,7 @@ describe Ci::BuildPolicy, :models do
context 'when public builds are enabled' do
it 'includes ability to read build' do
- expect(policies).to include :read_build
+ expect(policy).to be_allowed :read_build
end
end
@@ -47,7 +47,7 @@ describe Ci::BuildPolicy, :models do
include_context 'public pipelines disabled'
it 'does not include ability to read build' do
- expect(policies).not_to include :read_build
+ expect(policy).not_to be_allowed :read_build
end
end
end
@@ -62,7 +62,7 @@ describe Ci::BuildPolicy, :models do
context 'when public builds are enabled' do
it 'includes ability to read build' do
- expect(policies).to include :read_build
+ expect(policy).to be_allowed :read_build
end
end
@@ -70,7 +70,7 @@ describe Ci::BuildPolicy, :models do
include_context 'public pipelines disabled'
it 'does not include ability to read build' do
- expect(policies).not_to include :read_build
+ expect(policy).not_to be_allowed :read_build
end
end
end
@@ -82,7 +82,7 @@ describe Ci::BuildPolicy, :models do
context 'when public builds are enabled' do
it 'includes ability to read build' do
- expect(policies).to include :read_build
+ expect(policy).to be_allowed :read_build
end
end
@@ -90,61 +90,63 @@ describe Ci::BuildPolicy, :models do
include_context 'public pipelines disabled'
it 'does not include ability to read build' do
- expect(policies).to include :read_build
+ expect(policy).to be_allowed :read_build
end
end
end
end
- describe 'rules for manual actions' do
+ describe 'rules for protected ref' do
let(:project) { create(:project) }
+ let(:build) { create(:ci_build, ref: 'some-ref', pipeline: pipeline) }
before do
project.add_developer(user)
end
- context 'when branch build is assigned to is protected' do
+ context 'when no one can push or merge to the branch' do
before do
create(:protected_branch, :no_one_can_push,
- name: 'some-ref', project: project)
+ name: build.ref, project: project)
end
- context 'when build is a manual action' do
- let(:build) do
- create(:ci_build, :manual, ref: 'some-ref', pipeline: pipeline)
- end
-
- it 'does not include ability to update build' do
- expect(policies).not_to include :update_build
- end
+ it 'does not include ability to update build' do
+ expect(policy).to be_disallowed :update_build
end
+ end
- context 'when build is not a manual action' do
- let(:build) do
- create(:ci_build, ref: 'some-ref', pipeline: pipeline)
- end
+ context 'when developers can push to the branch' do
+ before do
+ create(:protected_branch, :developers_can_merge,
+ name: build.ref, project: project)
+ end
- it 'includes ability to update build' do
- expect(policies).to include :update_build
- end
+ it 'includes ability to update build' do
+ expect(policy).to be_allowed :update_build
end
end
- context 'when branch build is assigned to is not protected' do
- context 'when build is a manual action' do
- let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
+ context 'when no one can create the tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: build.ref, project: project)
- it 'includes ability to update build' do
- expect(policies).to include :update_build
- end
+ build.update(tag: true)
+ end
+
+ it 'does not include ability to update build' do
+ expect(policy).to be_disallowed :update_build
end
+ end
- context 'when build is not a manual action' do
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ context 'when no one can create the tag but it is not a tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: build.ref, project: project)
+ end
- it 'includes ability to update build' do
- expect(policies).to include :update_build
- end
+ it 'includes ability to update build' do
+ expect(policy).to be_allowed :update_build
end
end
end
diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb
new file mode 100644
index 00000000000..b11b06d301f
--- /dev/null
+++ b/spec/policies/ci/pipeline_policy_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper'
+
+describe Ci::PipelinePolicy, :models do
+ let(:user) { create(:user) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+
+ let(:policy) do
+ described_class.new(user, pipeline)
+ end
+
+ describe 'rules' do
+ describe 'rules for protected ref' do
+ let(:project) { create(:project) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when no one can push or merge to the branch' do
+ before do
+ create(:protected_branch, :no_one_can_push,
+ name: pipeline.ref, project: project)
+ end
+
+ it 'does not include ability to update pipeline' do
+ expect(policy).to be_disallowed :update_pipeline
+ end
+ end
+
+ context 'when developers can push to the branch' do
+ before do
+ create(:protected_branch, :developers_can_merge,
+ name: pipeline.ref, project: project)
+ end
+
+ it 'includes ability to update pipeline' do
+ expect(policy).to be_allowed :update_pipeline
+ end
+ end
+
+ context 'when no one can create the tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: pipeline.ref, project: project)
+
+ pipeline.update(tag: true)
+ end
+
+ it 'does not include ability to update pipeline' do
+ expect(policy).to be_disallowed :update_pipeline
+ end
+ end
+
+ context 'when no one can create the tag but it is not a tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: pipeline.ref, project: project)
+ end
+
+ it 'includes ability to update pipeline' do
+ expect(policy).to be_allowed :update_pipeline
+ end
+ end
+ end
+ end
+end
diff --git a/spec/policies/ci/trigger_policy_spec.rb b/spec/policies/ci/trigger_policy_spec.rb
index 63ad5eb7322..3d3e3d3755b 100644
--- a/spec/policies/ci/trigger_policy_spec.rb
+++ b/spec/policies/ci/trigger_policy_spec.rb
@@ -1,41 +1,41 @@
require 'spec_helper'
-describe Ci::TriggerPolicy, :models do
+describe Ci::TriggerPolicy do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:trigger) { create(:ci_trigger, project: project, owner: owner) }
let(:policies) do
- described_class.abilities(user, trigger).to_set
+ described_class.new(user, trigger)
end
shared_examples 'allows to admin and manage trigger' do
it 'does include ability to admin trigger' do
- expect(policies).to include :admin_trigger
+ expect(policies).to be_allowed :admin_trigger
end
it 'does include ability to manage trigger' do
- expect(policies).to include :manage_trigger
+ expect(policies).to be_allowed :manage_trigger
end
end
shared_examples 'allows to manage trigger' do
it 'does not include ability to admin trigger' do
- expect(policies).not_to include :admin_trigger
+ expect(policies).not_to be_allowed :admin_trigger
end
it 'does include ability to manage trigger' do
- expect(policies).to include :manage_trigger
+ expect(policies).to be_allowed :manage_trigger
end
end
shared_examples 'disallows to admin and manage trigger' do
it 'does not include ability to admin trigger' do
- expect(policies).not_to include :admin_trigger
+ expect(policies).not_to be_allowed :admin_trigger
end
it 'does not include ability to manage trigger' do
- expect(policies).not_to include :manage_trigger
+ expect(policies).not_to be_allowed :manage_trigger
end
end
diff --git a/spec/policies/deploy_key_policy_spec.rb b/spec/policies/deploy_key_policy_spec.rb
index 28e10f0bfe2..ca7b7fe7ef7 100644
--- a/spec/policies/deploy_key_policy_spec.rb
+++ b/spec/policies/deploy_key_policy_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe DeployKeyPolicy, models: true do
- subject { described_class.abilities(current_user, deploy_key).to_set }
+describe DeployKeyPolicy do
+ subject { described_class.new(current_user, deploy_key) }
describe 'updating a deploy_key' do
context 'when a regular user' do
@@ -16,7 +16,7 @@ describe DeployKeyPolicy, models: true do
project.deploy_keys << deploy_key
end
- it { is_expected.to include(:update_deploy_key) }
+ it { is_expected.to be_allowed(:update_deploy_key) }
end
context 'tries to update private deploy key attached to other project' do
@@ -27,13 +27,13 @@ describe DeployKeyPolicy, models: true do
other_project.deploy_keys << deploy_key
end
- it { is_expected.not_to include(:update_deploy_key) }
+ it { is_expected.to be_disallowed(:update_deploy_key) }
end
context 'tries to update public deploy key' do
let(:deploy_key) { create(:another_deploy_key, public: true) }
- it { is_expected.not_to include(:update_deploy_key) }
+ it { is_expected.to be_disallowed(:update_deploy_key) }
end
end
@@ -43,13 +43,13 @@ describe DeployKeyPolicy, models: true do
context ' tries to update private deploy key' do
let(:deploy_key) { create(:deploy_key, public: false) }
- it { is_expected.to include(:update_deploy_key) }
+ it { is_expected.to be_allowed(:update_deploy_key) }
end
context 'when an admin user tries to update public deploy key' do
let(:deploy_key) { create(:another_deploy_key, public: true) }
- it { is_expected.to include(:update_deploy_key) }
+ it { is_expected.to be_allowed(:update_deploy_key) }
end
end
end
diff --git a/spec/policies/environment_policy_spec.rb b/spec/policies/environment_policy_spec.rb
index 650432520bb..035e20c7452 100644
--- a/spec/policies/environment_policy_spec.rb
+++ b/spec/policies/environment_policy_spec.rb
@@ -8,8 +8,8 @@ describe EnvironmentPolicy do
create(:environment, :with_review_app, project: project)
end
- let(:policies) do
- described_class.abilities(user, environment).to_set
+ let(:policy) do
+ described_class.new(user, environment)
end
describe '#rules' do
@@ -17,7 +17,7 @@ describe EnvironmentPolicy do
let(:project) { create(:project, :private) }
it 'does not include ability to stop environment' do
- expect(policies).not_to include :stop_environment
+ expect(policy).to be_disallowed :stop_environment
end
end
@@ -25,7 +25,7 @@ describe EnvironmentPolicy do
let(:project) { create(:project, :public) }
it 'does not include ability to stop environment' do
- expect(policies).not_to include :stop_environment
+ expect(policy).to be_disallowed :stop_environment
end
end
@@ -38,7 +38,7 @@ describe EnvironmentPolicy do
context 'when team member has ability to stop environment' do
it 'does includes ability to stop environment' do
- expect(policies).to include :stop_environment
+ expect(policy).to be_allowed :stop_environment
end
end
@@ -49,7 +49,7 @@ describe EnvironmentPolicy do
end
it 'does not include ability to stop environment' do
- expect(policies).not_to include :stop_environment
+ expect(policy).to be_disallowed :stop_environment
end
end
end
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
new file mode 100644
index 00000000000..a6bf70c1e09
--- /dev/null
+++ b/spec/policies/global_policy_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+describe GlobalPolicy do
+ let(:current_user) { create(:user) }
+ let(:user) { create(:user) }
+
+ subject { described_class.new(current_user, [user]) }
+
+ describe "reading the list of users" do
+ context "for a logged in user" do
+ it { is_expected.to be_allowed(:read_users_list) }
+ end
+
+ context "for an anonymous user" do
+ let(:current_user) { nil }
+
+ context "when the public level is restricted" do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it { is_expected.not_to be_allowed(:read_users_list) }
+ end
+
+ context "when the public level is not restricted" do
+ before do
+ stub_application_setting(restricted_visibility_levels: [])
+ end
+
+ it { is_expected.to be_allowed(:read_users_list) }
+ end
+ end
+
+ context "for an admin" do
+ let(:current_user) { create(:admin) }
+
+ context "when the public level is restricted" do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it { is_expected.to be_allowed(:read_users_list) }
+ end
+
+ context "when the public level is not restricted" do
+ before do
+ stub_application_setting(restricted_visibility_levels: [])
+ end
+
+ it { is_expected.to be_allowed(:read_users_list) }
+ end
+ end
+ end
+end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index a8331ceb5ff..b17a93e3fbe 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GroupPolicy, models: true do
+describe GroupPolicy do
let(:guest) { create(:user) }
let(:reporter) { create(:user) }
let(:developer) { create(:user) }
@@ -36,16 +36,24 @@ describe GroupPolicy, models: true do
group.add_owner(owner)
end
- subject { described_class.abilities(current_user, group).to_set }
+ subject { described_class.new(current_user, group) }
+
+ def expect_allowed(*permissions)
+ permissions.each { |p| is_expected.to be_allowed(p) }
+ end
+
+ def expect_disallowed(*permissions)
+ permissions.each { |p| is_expected.not_to be_allowed(p) }
+ end
context 'with no user' do
let(:current_user) { nil }
it do
- is_expected.to include(:read_group)
- is_expected.not_to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_disallowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -53,10 +61,10 @@ describe GroupPolicy, models: true do
let(:current_user) { guest }
it do
- is_expected.to include(:read_group)
- is_expected.not_to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_disallowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -64,10 +72,10 @@ describe GroupPolicy, models: true do
let(:current_user) { reporter }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -75,10 +83,10 @@ describe GroupPolicy, models: true do
let(:current_user) { developer }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -86,10 +94,10 @@ describe GroupPolicy, models: true do
let(:current_user) { master }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -97,10 +105,10 @@ describe GroupPolicy, models: true do
let(:current_user) { owner }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*master_permissions)
- is_expected.to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*master_permissions)
+ expect_allowed(*owner_permissions)
end
end
@@ -108,10 +116,10 @@ describe GroupPolicy, models: true do
let(:current_user) { admin }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*master_permissions)
- is_expected.to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*master_permissions)
+ expect_allowed(*owner_permissions)
end
end
@@ -130,16 +138,16 @@ describe GroupPolicy, models: true do
nested_group.add_owner(owner)
end
- subject { described_class.abilities(current_user, nested_group).to_set }
+ subject { described_class.new(current_user, nested_group) }
context 'with no user' do
let(:current_user) { nil }
it do
- is_expected.not_to include(:read_group)
- is_expected.not_to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_disallowed(:read_group)
+ expect_disallowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -147,10 +155,10 @@ describe GroupPolicy, models: true do
let(:current_user) { guest }
it do
- is_expected.to include(:read_group)
- is_expected.not_to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_disallowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -158,10 +166,10 @@ describe GroupPolicy, models: true do
let(:current_user) { reporter }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -169,10 +177,10 @@ describe GroupPolicy, models: true do
let(:current_user) { developer }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -180,10 +188,10 @@ describe GroupPolicy, models: true do
let(:current_user) { master }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -191,10 +199,10 @@ describe GroupPolicy, models: true do
let(:current_user) { owner }
it do
- is_expected.to include(:read_group)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*master_permissions)
- is_expected.to include(*owner_permissions)
+ expect_allowed(:read_group)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*master_permissions)
+ expect_allowed(*owner_permissions)
end
end
end
diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb
index 4a07c864428..279b96fb2af 100644
--- a/spec/policies/issue_policy_spec.rb
+++ b/spec/policies/issue_policy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe IssuePolicy, models: true do
+describe IssuePolicy do
let(:guest) { create(:user) }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
@@ -9,7 +9,7 @@ describe IssuePolicy, models: true do
let(:reporter_from_group_link) { create(:user) }
def permissions(user, issue)
- described_class.abilities(user, issue).to_set
+ described_class.new(user, issue)
end
context 'a private project' do
@@ -30,42 +30,42 @@ describe IssuePolicy, models: true do
end
it 'does not allow non-members to read issues' do
- expect(permissions(non_member, issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(non_member, issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(non_member, issue)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(non_member, issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows guests to read issues' do
- expect(permissions(guest, issue)).to include(:read_issue)
- expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(guest, issue)).to be_allowed(:read_issue)
+ expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue)
- expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
- expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue)
+ expect(permissions(guest, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin issues' do
- expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin issues' do
- expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their issues' do
- expect(permissions(author, issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, issue)).not_to include(:admin_issue)
+ expect(permissions(author, issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(author, issue)).to be_disallowed(:admin_issue)
- expect(permissions(author, issue_no_assignee)).to include(:read_issue)
- expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(author, issue_no_assignee)).to be_allowed(:read_issue)
+ expect(permissions(author, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their issues' do
- expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, issue)).not_to include(:admin_issue)
+ expect(permissions(assignee, issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(assignee, issue)).to be_disallowed(:admin_issue)
- expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
- expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(assignee, issue_no_assignee)).to be_allowed(:read_issue)
+ expect(permissions(assignee, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue)
end
context 'with confidential issues' do
@@ -73,37 +73,37 @@ describe IssuePolicy, models: true do
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow non-members to read confidential issues' do
- expect(permissions(non_member, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(non_member, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(non_member, confidential_issue)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(non_member, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
it 'does not allow guests to read confidential issues' do
- expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin confidential issues' do
- expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, confidential_issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, confidential_issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin confidential issues' do
- expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, confidential_issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their confidential issues' do
- expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
+ expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(author, confidential_issue)).to be_disallowed(:admin_issue)
- expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their confidential issues' do
- expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
+ expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(assignee, confidential_issue)).to be_disallowed(:admin_issue)
- expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
end
end
@@ -123,37 +123,37 @@ describe IssuePolicy, models: true do
end
it 'allows guests to read issues' do
- expect(permissions(guest, issue)).to include(:read_issue)
- expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(guest, issue)).to be_allowed(:read_issue)
+ expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue)
- expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
- expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue)
+ expect(permissions(guest, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin issues' do
- expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin issues' do
- expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their issues' do
- expect(permissions(author, issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, issue)).not_to include(:admin_issue)
+ expect(permissions(author, issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(author, issue)).to be_disallowed(:admin_issue)
- expect(permissions(author, issue_no_assignee)).to include(:read_issue)
- expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(author, issue_no_assignee)).to be_allowed(:read_issue)
+ expect(permissions(author, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their issues' do
- expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, issue)).not_to include(:admin_issue)
+ expect(permissions(assignee, issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(assignee, issue)).to be_disallowed(:admin_issue)
- expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
- expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ expect(permissions(assignee, issue_no_assignee)).to be_allowed(:read_issue)
+ expect(permissions(assignee, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue)
end
context 'with confidential issues' do
@@ -161,32 +161,32 @@ describe IssuePolicy, models: true do
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow guests to read confidential issues' do
- expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin confidential issues' do
- expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, confidential_issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, confidential_issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporter from group links to read, update, and admin confidential issues' do
- expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, confidential_issue)).to be_allowed(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to be_allowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their confidential issues' do
- expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
+ expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(author, confidential_issue)).to be_disallowed(:admin_issue)
- expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their confidential issues' do
- expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
+ expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :update_issue)
+ expect(permissions(assignee, confidential_issue)).to be_disallowed(:admin_issue)
- expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :update_issue, :admin_issue)
end
end
end
diff --git a/spec/policies/personal_snippet_policy_spec.rb b/spec/policies/personal_snippet_policy_spec.rb
index 58aa1145c9e..b70c8646a3d 100644
--- a/spec/policies/personal_snippet_policy_spec.rb
+++ b/spec/policies/personal_snippet_policy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe PersonalSnippetPolicy, models: true do
+describe PersonalSnippetPolicy do
let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) }
let(:admin_user) { create(:user, :admin) }
@@ -14,7 +14,7 @@ describe PersonalSnippetPolicy, models: true do
end
def permissions(user)
- described_class.abilities(user, snippet).to_set
+ described_class.new(user, snippet)
end
context 'public snippet' do
@@ -24,9 +24,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(nil) }
it do
- is_expected.to include(:read_personal_snippet)
- is_expected.not_to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_allowed(:read_personal_snippet)
+ is_expected.to be_disallowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -34,9 +34,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(regular_user) }
it do
- is_expected.to include(:read_personal_snippet)
- is_expected.to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_allowed(:read_personal_snippet)
+ is_expected.to be_allowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -44,9 +44,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(snippet.author) }
it do
- is_expected.to include(:read_personal_snippet)
- is_expected.to include(:comment_personal_snippet)
- is_expected.to include(*author_permissions)
+ is_expected.to be_allowed(:read_personal_snippet)
+ is_expected.to be_allowed(:comment_personal_snippet)
+ is_expected.to be_allowed(*author_permissions)
end
end
end
@@ -58,9 +58,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(nil) }
it do
- is_expected.not_to include(:read_personal_snippet)
- is_expected.not_to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_disallowed(:read_personal_snippet)
+ is_expected.to be_disallowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -68,9 +68,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(regular_user) }
it do
- is_expected.to include(:read_personal_snippet)
- is_expected.to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_allowed(:read_personal_snippet)
+ is_expected.to be_allowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -78,9 +78,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(external_user) }
it do
- is_expected.not_to include(:read_personal_snippet)
- is_expected.not_to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_disallowed(:read_personal_snippet)
+ is_expected.to be_disallowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -88,9 +88,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(snippet.author) }
it do
- is_expected.to include(:read_personal_snippet)
- is_expected.to include(:comment_personal_snippet)
- is_expected.to include(*author_permissions)
+ is_expected.to be_allowed(:read_personal_snippet)
+ is_expected.to be_allowed(:comment_personal_snippet)
+ is_expected.to be_allowed(*author_permissions)
end
end
end
@@ -102,9 +102,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(nil) }
it do
- is_expected.not_to include(:read_personal_snippet)
- is_expected.not_to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_disallowed(:read_personal_snippet)
+ is_expected.to be_disallowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -112,9 +112,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(regular_user) }
it do
- is_expected.not_to include(:read_personal_snippet)
- is_expected.not_to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_disallowed(:read_personal_snippet)
+ is_expected.to be_disallowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -122,9 +122,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(external_user) }
it do
- is_expected.not_to include(:read_personal_snippet)
- is_expected.not_to include(:comment_personal_snippet)
- is_expected.not_to include(*author_permissions)
+ is_expected.to be_disallowed(:read_personal_snippet)
+ is_expected.to be_disallowed(:comment_personal_snippet)
+ is_expected.to be_disallowed(*author_permissions)
end
end
@@ -132,9 +132,9 @@ describe PersonalSnippetPolicy, models: true do
subject { permissions(snippet.author) }
it do
- is_expected.to include(:read_personal_snippet)
- is_expected.to include(:comment_personal_snippet)
- is_expected.to include(*author_permissions)
+ is_expected.to be_allowed(:read_personal_snippet)
+ is_expected.to be_allowed(:comment_personal_snippet)
+ is_expected.to be_allowed(*author_permissions)
end
end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index d70e15f006b..1f51ced1beb 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectPolicy, models: true do
+describe ProjectPolicy do
let(:guest) { create(:user) }
let(:reporter) { create(:user) }
let(:dev) { create(:user) }
@@ -73,37 +73,87 @@ describe ProjectPolicy, models: true do
project.team << [reporter, :reporter]
end
+ def expect_allowed(*permissions)
+ permissions.each { |p| is_expected.to be_allowed(p) }
+ end
+
+ def expect_disallowed(*permissions)
+ permissions.each { |p| is_expected.not_to be_allowed(p) }
+ end
+
it 'does not include the read_issue permission when the issue author is not a member of the private project' do
project = create(:empty_project, :private)
issue = create(:issue, project: project)
user = issue.author
- expect(project.team.member?(issue.author)).to eq(false)
+ expect(project.team.member?(issue.author)).to be false
+
+ expect(Ability).not_to be_allowed(user, :read_issue, project)
+ end
+
+ context 'when the feature is disabled' do
+ subject { described_class.new(owner, project) }
- expect(BasePolicy.class_for(project).abilities(user, project).can_set)
- .not_to include(:read_issue)
+ before do
+ project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
+ end
- expect(Ability.allowed?(user, :read_issue, project)).to be_falsy
+ it 'does not include the wiki permissions' do
+ expect_disallowed :read_wiki, :create_wiki, :update_wiki, :admin_wiki, :download_wiki_code
+ end
end
- it 'does not include the wiki permissions when the feature is disabled' do
- project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
- wiki_permissions = [:read_wiki, :create_wiki, :update_wiki, :admin_wiki, :download_wiki_code]
+ context 'issues feature' do
+ subject { described_class.new(owner, project) }
- permissions = described_class.abilities(owner, project).to_set
+ context 'when the feature is disabled' do
+ it 'does not include the issues permissions' do
+ project.issues_enabled = false
+ project.save!
+
+ expect_disallowed :read_issue, :create_issue, :update_issue, :admin_issue
+ end
+ end
- expect(permissions).not_to include(*wiki_permissions)
+ context 'when the feature is disabled and external tracker configured' do
+ it 'does not include the issues permissions' do
+ create(:jira_service, project: project)
+
+ project.issues_enabled = false
+ project.save!
+
+ expect_disallowed :read_issue, :create_issue, :update_issue, :admin_issue
+ end
+ end
+ end
+
+ context 'when a project has pending invites, and the current user is anonymous' do
+ let(:group) { create(:group, :public) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
+ let(:user_permissions) { [:create_project, :create_issue, :create_note, :upload_file] }
+ let(:anonymous_permissions) { guest_permissions - user_permissions }
+
+ subject { described_class.new(nil, project) }
+
+ before do
+ create(:group_member, :invited, group: group)
+ end
+
+ it 'does not grant owner access' do
+ expect_allowed(*anonymous_permissions)
+ expect_disallowed(*user_permissions)
+ end
end
context 'abilities for non-public projects' do
let(:project) { create(:empty_project, namespace: owner.namespace) }
- subject { described_class.abilities(current_user, project).to_set }
+ subject { described_class.new(current_user, project) }
context 'with no user' do
let(:current_user) { nil }
- it { is_expected.to be_empty }
+ it { is_expected.to be_banned }
end
context 'guests' do
@@ -114,18 +164,18 @@ describe ProjectPolicy, models: true do
end
it do
- is_expected.to include(*guest_permissions)
- is_expected.not_to include(*reporter_public_build_permissions)
- is_expected.not_to include(*team_member_reporter_permissions)
- is_expected.not_to include(*developer_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(*guest_permissions)
+ expect_disallowed(*reporter_public_build_permissions)
+ expect_disallowed(*team_member_reporter_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
context 'public builds enabled' do
it do
- is_expected.to include(*guest_permissions)
- is_expected.to include(:read_build, :read_pipeline)
+ expect_allowed(*guest_permissions)
+ expect_allowed(:read_build, :read_pipeline)
end
end
@@ -135,8 +185,8 @@ describe ProjectPolicy, models: true do
end
it do
- is_expected.to include(*guest_permissions)
- is_expected.not_to include(:read_build, :read_pipeline)
+ expect_allowed(*guest_permissions)
+ expect_disallowed(:read_build, :read_pipeline)
end
end
@@ -147,8 +197,8 @@ describe ProjectPolicy, models: true do
end
it do
- is_expected.not_to include(:read_build)
- is_expected.to include(:read_pipeline)
+ expect_disallowed(:read_build)
+ expect_allowed(:read_pipeline)
end
end
end
@@ -157,12 +207,13 @@ describe ProjectPolicy, models: true do
let(:current_user) { reporter }
it do
- is_expected.to include(*guest_permissions)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*team_member_reporter_permissions)
- is_expected.not_to include(*developer_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*team_member_reporter_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -170,12 +221,12 @@ describe ProjectPolicy, models: true do
let(:current_user) { dev }
it do
- is_expected.to include(*guest_permissions)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*team_member_reporter_permissions)
- is_expected.to include(*developer_permissions)
- is_expected.not_to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*team_member_reporter_permissions)
+ expect_allowed(*developer_permissions)
+ expect_disallowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -183,12 +234,12 @@ describe ProjectPolicy, models: true do
let(:current_user) { master }
it do
- is_expected.to include(*guest_permissions)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*team_member_reporter_permissions)
- is_expected.to include(*developer_permissions)
- is_expected.to include(*master_permissions)
- is_expected.not_to include(*owner_permissions)
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*team_member_reporter_permissions)
+ expect_allowed(*developer_permissions)
+ expect_allowed(*master_permissions)
+ expect_disallowed(*owner_permissions)
end
end
@@ -196,12 +247,12 @@ describe ProjectPolicy, models: true do
let(:current_user) { owner }
it do
- is_expected.to include(*guest_permissions)
- is_expected.to include(*reporter_permissions)
- is_expected.to include(*team_member_reporter_permissions)
- is_expected.to include(*developer_permissions)
- is_expected.to include(*master_permissions)
- is_expected.to include(*owner_permissions)
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_allowed(*team_member_reporter_permissions)
+ expect_allowed(*developer_permissions)
+ expect_allowed(*master_permissions)
+ expect_allowed(*owner_permissions)
end
end
@@ -209,12 +260,12 @@ describe ProjectPolicy, models: true do
let(:current_user) { admin }
it do
- is_expected.to include(*guest_permissions)
- is_expected.to include(*reporter_permissions)
- is_expected.not_to include(*team_member_reporter_permissions)
- is_expected.to include(*developer_permissions)
- is_expected.to include(*master_permissions)
- is_expected.to include(*owner_permissions)
+ expect_allowed(*guest_permissions)
+ expect_allowed(*reporter_permissions)
+ expect_disallowed(*team_member_reporter_permissions)
+ expect_allowed(*developer_permissions)
+ expect_allowed(*master_permissions)
+ expect_allowed(*owner_permissions)
end
end
end
diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb
index d2b2528c57a..bae35ee31c6 100644
--- a/spec/policies/project_snippet_policy_spec.rb
+++ b/spec/policies/project_snippet_policy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProjectSnippetPolicy, models: true do
+describe ProjectSnippetPolicy do
let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) }
let(:project) { create(:empty_project, :public) }
@@ -15,7 +15,15 @@ describe ProjectSnippetPolicy, models: true do
def abilities(user, snippet_visibility)
snippet = create(:project_snippet, snippet_visibility, project: project)
- described_class.abilities(user, snippet).to_set
+ described_class.new(user, snippet)
+ end
+
+ def expect_allowed(*permissions)
+ permissions.each { |p| is_expected.to be_allowed(p) }
+ end
+
+ def expect_disallowed(*permissions)
+ permissions.each { |p| is_expected.not_to be_allowed(p) }
end
context 'public snippet' do
@@ -23,8 +31,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(nil, :public) }
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -32,8 +40,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(regular_user, :public) }
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -41,8 +49,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(external_user, :public) }
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
end
@@ -52,8 +60,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(nil, :internal) }
it do
- is_expected.not_to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_disallowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -61,8 +69,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(regular_user, :internal) }
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -70,8 +78,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(external_user, :internal) }
it do
- is_expected.not_to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_disallowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -83,8 +91,8 @@ describe ProjectSnippetPolicy, models: true do
end
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
end
@@ -94,8 +102,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(nil, :private) }
it do
- is_expected.not_to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_disallowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -103,19 +111,19 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(regular_user, :private) }
it do
- is_expected.not_to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_disallowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
context 'snippet author' do
let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) }
- subject { described_class.abilities(regular_user, snippet).to_set }
+ subject { described_class.new(regular_user, snippet) }
it do
- is_expected.to include(:read_project_snippet)
- is_expected.to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_allowed(*author_permissions)
end
end
@@ -127,8 +135,8 @@ describe ProjectSnippetPolicy, models: true do
end
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -140,8 +148,8 @@ describe ProjectSnippetPolicy, models: true do
end
it do
- is_expected.to include(:read_project_snippet)
- is_expected.not_to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_disallowed(*author_permissions)
end
end
@@ -149,8 +157,8 @@ describe ProjectSnippetPolicy, models: true do
subject { abilities(create(:admin), :private) }
it do
- is_expected.to include(:read_project_snippet)
- is_expected.to include(*author_permissions)
+ expect_allowed(:read_project_snippet)
+ expect_allowed(*author_permissions)
end
end
end
diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb
index d5761390d39..6593a6ca3b9 100644
--- a/spec/policies/user_policy_spec.rb
+++ b/spec/policies/user_policy_spec.rb
@@ -1,37 +1,37 @@
require 'spec_helper'
-describe UserPolicy, models: true do
+describe UserPolicy do
let(:current_user) { create(:user) }
let(:user) { create(:user) }
- subject { described_class.abilities(current_user, user).to_set }
+ subject { described_class.new(current_user, user) }
describe "reading a user's information" do
- it { is_expected.to include(:read_user) }
+ it { is_expected.to be_allowed(:read_user) }
end
describe "destroying a user" do
context "when a regular user tries to destroy another regular user" do
- it { is_expected.not_to include(:destroy_user) }
+ it { is_expected.not_to be_allowed(:destroy_user) }
end
context "when a regular user tries to destroy themselves" do
let(:current_user) { user }
- it { is_expected.to include(:destroy_user) }
+ it { is_expected.to be_allowed(:destroy_user) }
end
context "when an admin user tries to destroy a regular user" do
let(:current_user) { create(:user, :admin) }
- it { is_expected.to include(:destroy_user) }
+ it { is_expected.to be_allowed(:destroy_user) }
end
context "when an admin user tries to destroy a ghost user" do
let(:current_user) { create(:user, :admin) }
let(:user) { create(:user, :ghost) }
- it { is_expected.not_to include(:destroy_user) }
+ it { is_expected.not_to be_allowed(:destroy_user) }
end
end
end
diff --git a/spec/presenters/ci/build_presenter_spec.rb b/spec/presenters/ci/build_presenter_spec.rb
index 518e97d17a1..f05d5c7fce5 100644
--- a/spec/presenters/ci/build_presenter_spec.rb
+++ b/spec/presenters/ci/build_presenter_spec.rb
@@ -85,7 +85,7 @@ describe Ci::BuildPresenter do
describe 'quack like a Ci::Build permission-wise' do
context 'user is not allowed' do
- let(:project) { build_stubbed(:empty_project, public_builds: false) }
+ let(:project) { create(:empty_project, public_builds: false) }
it 'returns false' do
expect(presenter.can?(nil, :read_build)).to be_falsy
@@ -93,7 +93,7 @@ describe Ci::BuildPresenter do
end
context 'user is allowed' do
- let(:project) { build_stubbed(:empty_project, :public) }
+ let(:project) { create(:empty_project, :public) }
it 'returns true' do
expect(presenter.can?(nil, :read_build)).to be_truthy
diff --git a/spec/presenters/ci/group_variable_presenter_spec.rb b/spec/presenters/ci/group_variable_presenter_spec.rb
new file mode 100644
index 00000000000..d404028405b
--- /dev/null
+++ b/spec/presenters/ci/group_variable_presenter_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+describe Ci::GroupVariablePresenter do
+ include Gitlab::Routing.url_helpers
+
+ let(:group) { create(:group) }
+ let(:variable) { create(:ci_group_variable, group: group) }
+
+ subject(:presenter) do
+ described_class.new(variable)
+ end
+
+ it 'inherits from Gitlab::View::Presenter::Delegated' do
+ expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated)
+ end
+
+ describe '#initialize' do
+ it 'takes a variable and optional params' do
+ expect { presenter }.not_to raise_error
+ end
+
+ it 'exposes variable' do
+ expect(presenter.variable).to eq(variable)
+ end
+
+ it 'forwards missing methods to variable' do
+ expect(presenter.key).to eq(variable.key)
+ end
+ end
+
+ describe '#placeholder' do
+ subject { described_class.new(variable).placeholder }
+
+ it { is_expected.to eq('GROUP_VARIABLE') }
+ end
+
+ describe '#form_path' do
+ context 'when variable is persisted' do
+ subject { described_class.new(variable).form_path }
+
+ it { is_expected.to eq(group_variable_path(group, variable)) }
+ end
+
+ context 'when variable is not persisted' do
+ let(:variable) { build(:ci_group_variable, group: group) }
+ subject { described_class.new(variable).form_path }
+
+ it { is_expected.to eq(group_variables_path(group)) }
+ end
+ end
+
+ describe '#edit_path' do
+ subject { described_class.new(variable).edit_path }
+
+ it { is_expected.to eq(group_variable_path(group, variable)) }
+ end
+
+ describe '#delete_path' do
+ subject { described_class.new(variable).delete_path }
+
+ it { is_expected.to eq(group_variable_path(group, variable)) }
+ end
+end
diff --git a/spec/presenters/ci/variable_presenter_spec.rb b/spec/presenters/ci/variable_presenter_spec.rb
new file mode 100644
index 00000000000..9e6aae7bcad
--- /dev/null
+++ b/spec/presenters/ci/variable_presenter_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+describe Ci::VariablePresenter do
+ include Gitlab::Routing.url_helpers
+
+ let(:project) { create(:empty_project) }
+ let(:variable) { create(:ci_variable, project: project) }
+
+ subject(:presenter) do
+ described_class.new(variable)
+ end
+
+ it 'inherits from Gitlab::View::Presenter::Delegated' do
+ expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated)
+ end
+
+ describe '#initialize' do
+ it 'takes a variable and optional params' do
+ expect { presenter }.not_to raise_error
+ end
+
+ it 'exposes variable' do
+ expect(presenter.variable).to eq(variable)
+ end
+
+ it 'forwards missing methods to variable' do
+ expect(presenter.key).to eq(variable.key)
+ end
+ end
+
+ describe '#placeholder' do
+ subject { described_class.new(variable).placeholder }
+
+ it { is_expected.to eq('PROJECT_VARIABLE') }
+ end
+
+ describe '#form_path' do
+ context 'when variable is persisted' do
+ subject { described_class.new(variable).form_path }
+
+ it { is_expected.to eq(project_variable_path(project, variable)) }
+ end
+
+ context 'when variable is not persisted' do
+ let(:variable) { build(:ci_variable, project: project) }
+ subject { described_class.new(variable).form_path }
+
+ it { is_expected.to eq(project_variables_path(project)) }
+ end
+ end
+
+ describe '#edit_path' do
+ subject { described_class.new(variable).edit_path }
+
+ it { is_expected.to eq(project_variable_path(project, variable)) }
+ end
+
+ describe '#delete_path' do
+ subject { described_class.new(variable).delete_path }
+
+ it { is_expected.to eq(project_variable_path(project, variable)) }
+ end
+end
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index f5a14b1d04d..c1a0313b13c 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -332,7 +332,31 @@ describe MergeRequestPresenter do
end
end
- context 'when target branch does not exists' do
+ context 'when target branch does not exist' do
+ it 'returns nil' do
+ allow(resource).to receive(:target_branch_exists?) { false }
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ describe '#target_branch_tree_path' do
+ subject do
+ described_class.new(resource, current_user: user)
+ .target_branch_tree_path
+ end
+
+ context 'when target branch exists' do
+ it 'returns path' do
+ allow(resource).to receive(:target_branch_exists?) { true }
+
+ is_expected
+ .to eq("/#{resource.target_project.full_path}/tree/#{resource.target_branch}")
+ end
+ end
+
+ context 'when target branch does not exist' do
it 'returns nil' do
allow(resource).to receive(:target_branch_exists?) { false }
@@ -355,7 +379,7 @@ describe MergeRequestPresenter do
end
end
- context 'when source branch does not exists' do
+ context 'when source branch does not exist' do
it 'returns nil' do
allow(resource).to receive(:source_branch_exists?) { false }
@@ -363,4 +387,17 @@ describe MergeRequestPresenter do
end
end
end
+
+ describe '#source_branch_with_namespace_link' do
+ subject do
+ described_class.new(resource, current_user: user).source_branch_with_namespace_link
+ end
+
+ it 'returns link' do
+ allow(resource).to receive(:source_branch_exists?) { true }
+
+ is_expected
+ .to eq("<a href=\"/#{resource.source_project.full_path}/tree/#{resource.source_branch}\">#{resource.source_branch}</a>")
+ end
+ end
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index c64499fc8c0..5a2e1b2cf2d 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -1,25 +1,31 @@
require 'spec_helper'
-require 'mime/types'
describe API::Branches do
let(:user) { create(:user) }
- let!(:project) { create(:project, :repository, creator: user) }
- let!(:master) { create(:project_member, :master, user: user, project: project) }
- let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } }
- let!(:branch_name) { 'feature' }
- let!(:branch_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
- let(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master")[:branch] }
+ let(:guest) { create(:user).tap { |u| project.add_guest(u) } }
+ let(:project) { create(:project, :repository, creator: user, path: 'my.project') }
+ let(:branch_name) { 'feature' }
+ let(:branch_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
+ let(:branch_with_dot) { project.repository.find_branch('ends-with.json') }
+ let(:branch_with_slash) { project.repository.find_branch('improve/awesome') }
+
+ let(:project_id) { project.id }
+ let(:current_user) { nil }
+
+ before do
+ project.add_master(user)
+ end
describe "GET /projects/:id/repository/branches" do
- let(:route) { "/projects/#{project.id}/repository/branches" }
+ let(:route) { "/projects/#{project_id}/repository/branches" }
shared_examples_for 'repository branches' do
it 'returns the repository branches' do
get api(route, current_user), per_page: 100
- expect(response).to have_http_status(200)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branches')
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
branch_names = json_response.map { |x| x['name'] }
expect(branch_names).to match_array(project.repository.branch_names)
end
@@ -34,10 +40,9 @@ describe API::Branches do
end
context 'when unauthenticated', 'and project is public' do
- it_behaves_like 'repository branches' do
- let(:project) { create(:project, :public, :repository) }
- let(:current_user) { nil }
- end
+ let(:project) { create(:project, :public, :repository) }
+
+ it_behaves_like 'repository branches'
end
context 'when unauthenticated', 'and project is private' do
@@ -47,9 +52,15 @@ describe API::Branches do
end
end
- context 'when authenticated', 'as a developer' do
- it_behaves_like 'repository branches' do
- let(:current_user) { user }
+ context 'when authenticated', 'as a master' do
+ let(:current_user) { user }
+
+ it_behaves_like 'repository branches'
+
+ context 'requesting with the escaped project full path' do
+ let(:project_id) { CGI.escape(project.full_path) }
+
+ it_behaves_like 'repository branches'
end
end
@@ -61,31 +72,15 @@ describe API::Branches do
end
describe "GET /projects/:id/repository/branches/:branch" do
- let(:route) { "/projects/#{project.id}/repository/branches/#{branch_name}" }
+ let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}" }
- shared_examples_for 'repository branch' do |merged: false|
+ shared_examples_for 'repository branch' do
it 'returns the repository branch' do
get api(route, current_user)
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['merged']).to eq(merged)
- expect(json_response['protected']).to eq(false)
- expect(json_response['developers_can_push']).to eq(false)
- expect(json_response['developers_can_merge']).to eq(false)
-
- json_commit = json_response['commit']
- expect(json_commit['id']).to eq(branch_sha)
- expect(json_commit).to have_key('short_id')
- expect(json_commit).to have_key('title')
- expect(json_commit).to have_key('message')
- expect(json_commit).to have_key('author_name')
- expect(json_commit).to have_key('author_email')
- expect(json_commit).to have_key('authored_date')
- expect(json_commit).to have_key('committer_name')
- expect(json_commit).to have_key('committer_email')
- expect(json_commit).to have_key('committed_date')
- expect(json_commit).to have_key('parent_ids')
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
end
context 'when branch does not exist' do
@@ -107,10 +102,9 @@ describe API::Branches do
end
context 'when unauthenticated', 'and project is public' do
- it_behaves_like 'repository branch' do
- let(:project) { create(:project, :public, :repository) }
- let(:current_user) { nil }
- end
+ let(:project) { create(:project, :public, :repository) }
+
+ it_behaves_like 'repository branch'
end
context 'when unauthenticated', 'and project is private' do
@@ -120,22 +114,41 @@ describe API::Branches do
end
end
- context 'when authenticated', 'as a developer' do
+ context 'when authenticated', 'as a master' do
let(:current_user) { user }
+
it_behaves_like 'repository branch'
context 'when branch contains a dot' do
let(:branch_name) { branch_with_dot.name }
- let(:branch_sha) { project.commit('master').sha }
it_behaves_like 'repository branch'
end
- context 'when branch is merged' do
- let(:branch_name) { 'merge-test' }
- let(:branch_sha) { project.commit('merge-test').sha }
+ context 'when branch contains a slash' do
+ let(:branch_name) { branch_with_slash.name }
+
+ it_behaves_like '404 response' do
+ let(:request) { get api(route, current_user) }
+ end
+ end
+
+ context 'when branch contains an escaped slash' do
+ let(:branch_name) { CGI.escape(branch_with_slash.name) }
+
+ it_behaves_like 'repository branch'
+ end
+
+ context 'requesting with the escaped project full path' do
+ let(:project_id) { CGI.escape(project.full_path) }
+
+ it_behaves_like 'repository branch'
- it_behaves_like 'repository branch', merged: true
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot.name }
+
+ it_behaves_like 'repository branch'
+ end
end
end
@@ -147,268 +160,348 @@ describe API::Branches do
end
describe 'PUT /projects/:id/repository/branches/:branch/protect' do
- context "when a protected branch doesn't already exist" do
- it 'protects a single branch' do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
+ let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}/protect" }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['commit']['id']).to eq(branch_sha)
- expect(json_response['protected']).to eq(true)
- expect(json_response['developers_can_push']).to eq(false)
- expect(json_response['developers_can_merge']).to eq(false)
- end
-
- it "protects a single branch with dots in the name" do
- put api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}/protect", user)
+ shared_examples_for 'repository new protected branch' do
+ it 'protects a single branch' do
+ put api(route, current_user)
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_with_dot.name)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
expect(json_response['protected']).to eq(true)
end
it 'protects a single branch and developers can push' do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
- developers_can_push: true
+ put api(route, current_user), developers_can_push: true
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
expect(json_response['protected']).to eq(true)
expect(json_response['developers_can_push']).to eq(true)
expect(json_response['developers_can_merge']).to eq(false)
end
it 'protects a single branch and developers can merge' do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
- developers_can_merge: true
+ put api(route, current_user), developers_can_merge: true
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
expect(json_response['protected']).to eq(true)
expect(json_response['developers_can_push']).to eq(false)
expect(json_response['developers_can_merge']).to eq(true)
end
it 'protects a single branch and developers can push and merge' do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
- developers_can_push: true, developers_can_merge: true
+ put api(route, current_user), developers_can_push: true, developers_can_merge: true
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['commit']['id']).to eq(branch_sha)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
expect(json_response['protected']).to eq(true)
expect(json_response['developers_can_push']).to eq(true)
expect(json_response['developers_can_merge']).to eq(true)
end
+
+ context 'when branch does not exist' do
+ let(:branch_name) { 'unknown' }
+
+ it_behaves_like '404 response' do
+ let(:request) { put api(route, current_user) }
+ let(:message) { '404 Branch Not Found' }
+ end
+ end
+
+ context 'when repository is disabled' do
+ include_context 'disabled repository'
+
+ it_behaves_like '403 response' do
+ let(:request) { put api(route, current_user) }
+ end
+ end
end
- context 'for an existing protected branch' do
- before do
- project.repository.add_branch(user, protected_branch.name, 'master')
+ context 'when unauthenticated', 'and project is private' do
+ it_behaves_like '404 response' do
+ let(:request) { put api(route) }
+ let(:message) { '404 Project Not Found' }
end
+ end
+
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { put api(route, guest) }
+ end
+ end
+
+ context 'when authenticated', 'as a master' do
+ let(:current_user) { user }
- context "when developers can push and merge" do
- let(:protected_branch) { create(:protected_branch, :developers_can_push, :developers_can_merge, project: project, name: 'protected_branch') }
+ context "when a protected branch doesn't already exist" do
+ it_behaves_like 'repository new protected branch'
- it 'updates that a developer cannot push or merge' do
- put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user),
- developers_can_push: false, developers_can_merge: false
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot.name }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(protected_branch.name)
- expect(json_response['protected']).to eq(true)
- expect(json_response['developers_can_push']).to eq(false)
- expect(json_response['developers_can_merge']).to eq(false)
+ it_behaves_like 'repository new protected branch'
end
- it "doesn't result in 0 access levels when 'developers_can_push' is switched off" do
- put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user),
- developers_can_push: false
+ context 'when branch contains a slash' do
+ let(:branch_name) { branch_with_slash.name }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(protected_branch.name)
- expect(protected_branch.reload.push_access_levels.first).to be_present
- expect(protected_branch.reload.push_access_levels.first.access_level).to eq(Gitlab::Access::MASTER)
+ it_behaves_like '404 response' do
+ let(:request) { put api(route, current_user) }
+ end
end
- it "doesn't result in 0 access levels when 'developers_can_merge' is switched off" do
- put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user),
- developers_can_merge: false
+ context 'when branch contains an escaped slash' do
+ let(:branch_name) { CGI.escape(branch_with_slash.name) }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(protected_branch.name)
- expect(protected_branch.reload.merge_access_levels.first).to be_present
- expect(protected_branch.reload.merge_access_levels.first.access_level).to eq(Gitlab::Access::MASTER)
+ it_behaves_like 'repository new protected branch'
+ end
+
+ context 'requesting with the escaped project full path' do
+ let(:project_id) { CGI.escape(project.full_path) }
+
+ it_behaves_like 'repository new protected branch'
+
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot.name }
+
+ it_behaves_like 'repository new protected branch'
+ end
end
end
- context "when developers cannot push or merge" do
- let(:protected_branch) { create(:protected_branch, project: project, name: 'protected_branch') }
+ context 'when protected branch already exists' do
+ before do
+ project.repository.add_branch(user, protected_branch.name, 'master')
+ end
+
+ context 'when developers can push and merge' do
+ let(:protected_branch) { create(:protected_branch, :developers_can_push, :developers_can_merge, project: project, name: 'protected_branch') }
+
+ it 'updates that a developer cannot push or merge' do
+ put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user),
+ developers_can_push: false, developers_can_merge: false
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(protected_branch.name)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(false)
+ expect(json_response['developers_can_merge']).to eq(false)
+ expect(protected_branch.reload.push_access_levels.first.access_level).to eq(Gitlab::Access::MASTER)
+ expect(protected_branch.reload.merge_access_levels.first.access_level).to eq(Gitlab::Access::MASTER)
+ end
+ end
+
+ context 'when developers cannot push or merge' do
+ let(:protected_branch) { create(:protected_branch, project: project, name: 'protected_branch') }
- it 'updates that a developer can push and merge' do
- put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user),
- developers_can_push: true, developers_can_merge: true
+ it 'updates that a developer can push and merge' do
+ put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user),
+ developers_can_push: true, developers_can_merge: true
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(protected_branch.name)
- expect(json_response['protected']).to eq(true)
- expect(json_response['developers_can_push']).to eq(true)
- expect(json_response['developers_can_merge']).to eq(true)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(protected_branch.name)
+ expect(json_response['protected']).to eq(true)
+ expect(json_response['developers_can_push']).to eq(true)
+ expect(json_response['developers_can_merge']).to eq(true)
+ end
end
end
end
+ end
- context "multiple API calls" do
- it "returns success when `protect` is called twice" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user)
+ describe 'PUT /projects/:id/repository/branches/:branch/unprotect' do
+ let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}/unprotect" }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['protected']).to eq(true)
- expect(json_response['developers_can_push']).to eq(false)
- expect(json_response['developers_can_merge']).to eq(false)
+ shared_examples_for 'repository unprotected branch' do
+ it 'unprotects a single branch' do
+ put api(route, current_user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq(CGI.unescape(branch_name))
+ expect(json_response['protected']).to eq(false)
end
- it "returns success when `protect` is called twice with `developers_can_push` turned on" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_push: true
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_push: true
+ context 'when branch does not exist' do
+ let(:branch_name) { 'unknown' }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['protected']).to eq(true)
- expect(json_response['developers_can_push']).to eq(true)
- expect(json_response['developers_can_merge']).to eq(false)
+ it_behaves_like '404 response' do
+ let(:request) { put api(route, current_user) }
+ let(:message) { '404 Branch Not Found' }
+ end
end
- it "returns success when `protect` is called twice with `developers_can_merge` turned on" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_merge: true
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_merge: true
+ context 'when repository is disabled' do
+ include_context 'disabled repository'
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['protected']).to eq(true)
- expect(json_response['developers_can_push']).to eq(false)
- expect(json_response['developers_can_merge']).to eq(true)
+ it_behaves_like '403 response' do
+ let(:request) { put api(route, current_user) }
+ end
end
end
- it "returns a 404 error if branch not found" do
- put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
- expect(response).to have_http_status(404)
+ context 'when unauthenticated', 'and project is private' do
+ it_behaves_like '404 response' do
+ let(:request) { put api(route) }
+ let(:message) { '404 Project Not Found' }
+ end
end
- it "returns a 403 error if guest" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", guest)
- expect(response).to have_http_status(403)
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { put api(route, guest) }
+ end
end
- end
- describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
- it "unprotects a single branch" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user)
- expect(response).to have_http_status(200)
+ context 'when authenticated', 'as a master' do
+ let(:current_user) { user }
+
+ context "when a protected branch doesn't already exist" do
+ it_behaves_like 'repository unprotected branch'
+
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot.name }
+
+ it_behaves_like 'repository unprotected branch'
+ end
+
+ context 'when branch contains a slash' do
+ let(:branch_name) { branch_with_slash.name }
+
+ it_behaves_like '404 response' do
+ let(:request) { put api(route, current_user) }
+ end
+ end
+
+ context 'when branch contains an escaped slash' do
+ let(:branch_name) { CGI.escape(branch_with_slash.name) }
- expect(json_response['name']).to eq(branch_name)
- expect(json_response['commit']['id']).to eq(branch_sha)
- expect(json_response['protected']).to eq(false)
+ it_behaves_like 'repository unprotected branch'
+ end
+
+ context 'requesting with the escaped project full path' do
+ let(:project_id) { CGI.escape(project.full_path) }
+
+ it_behaves_like 'repository unprotected branch'
+
+ context 'when branch contains a dot' do
+ let(:branch_name) { branch_with_dot.name }
+
+ it_behaves_like 'repository unprotected branch'
+ end
+ end
+ end
end
+ end
- it "update branches with dots in branch name" do
- put api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}/unprotect", user)
+ describe 'POST /projects/:id/repository/branches' do
+ let(:route) { "/projects/#{project_id}/repository/branches" }
- expect(response).to have_http_status(200)
- expect(json_response['name']).to eq(branch_with_dot.name)
- expect(json_response['protected']).to eq(false)
+ shared_examples_for 'repository new branch' do
+ it 'creates a new branch' do
+ post api(route, current_user), branch: 'feature1', ref: branch_sha
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(response).to match_response_schema('public_api/v4/branch')
+ expect(json_response['name']).to eq('feature1')
+ expect(json_response['commit']['id']).to eq(branch_sha)
+ end
+
+ context 'when repository is disabled' do
+ include_context 'disabled repository'
+
+ it_behaves_like '403 response' do
+ let(:request) { post api(route, current_user) }
+ end
+ end
end
- it "returns success when unprotect branch" do
- put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
- expect(response).to have_http_status(404)
+ context 'when unauthenticated', 'and project is private' do
+ it_behaves_like '404 response' do
+ let(:request) { post api(route) }
+ let(:message) { '404 Project Not Found' }
+ end
end
- it "returns success when unprotect branch again" do
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user)
- put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user)
- expect(response).to have_http_status(200)
+ context 'when authenticated', 'as a guest' do
+ it_behaves_like '403 response' do
+ let(:request) { post api(route, guest) }
+ end
end
- end
- describe "POST /projects/:id/repository/branches" do
- it "creates a new branch" do
- post api("/projects/#{project.id}/repository/branches", user),
- branch: 'feature1',
- ref: branch_sha
+ context 'when authenticated', 'as a master' do
+ let(:current_user) { user }
- expect(response).to have_http_status(201)
+ context "when a protected branch doesn't already exist" do
+ it_behaves_like 'repository new branch'
- expect(json_response['name']).to eq('feature1')
- expect(json_response['commit']['id']).to eq(branch_sha)
- end
+ context 'requesting with the escaped project full path' do
+ let(:project_id) { CGI.escape(project.full_path) }
- it "denies for user without push access" do
- post api("/projects/#{project.id}/repository/branches", guest),
- branch: branch_name,
- ref: branch_sha
- expect(response).to have_http_status(403)
+ it_behaves_like 'repository new branch'
+ end
+ end
end
it 'returns 400 if branch name is invalid' do
- post api("/projects/#{project.id}/repository/branches", user),
- branch: 'new design',
- ref: branch_sha
- expect(response).to have_http_status(400)
+ post api(route, user), branch: 'new design', ref: branch_sha
+
+ expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq('Branch name is invalid')
end
it 'returns 400 if branch already exists' do
- post api("/projects/#{project.id}/repository/branches", user),
- branch: 'new_design1',
- ref: branch_sha
- expect(response).to have_http_status(201)
-
- post api("/projects/#{project.id}/repository/branches", user),
- branch: 'new_design1',
- ref: branch_sha
- expect(response).to have_http_status(400)
+ post api(route, user), branch: 'new_design1', ref: branch_sha
+
+ expect(response).to have_gitlab_http_status(201)
+
+ post api(route, user), branch: 'new_design1', ref: branch_sha
+
+ expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq('Branch already exists')
end
it 'returns 400 if ref name is invalid' do
- post api("/projects/#{project.id}/repository/branches", user),
- branch: 'new_design3',
- ref: 'foo'
- expect(response).to have_http_status(400)
+ post api(route, user), branch: 'new_design3', ref: 'foo'
+
+ expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq('Invalid reference name')
end
end
- describe "DELETE /projects/:id/repository/branches/:branch" do
+ describe 'DELETE /projects/:id/repository/branches/:branch' do
before do
allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
end
- it "removes branch" do
+ it 'removes branch' do
delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user)
- expect(response).to have_http_status(204)
+ expect(response).to have_gitlab_http_status(204)
end
- it "removes a branch with dots in the branch name" do
+ it 'removes a branch with dots in the branch name' do
delete api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}", user)
- expect(response).to have_http_status(204)
+ expect(response).to have_gitlab_http_status(204)
end
it 'returns 404 if branch not exists' do
delete api("/projects/#{project.id}/repository/branches/foobar", user)
- expect(response).to have_http_status(404)
+
+ expect(response).to have_gitlab_http_status(404)
end
end
- describe "DELETE /projects/:id/repository/merged_branches" do
+ describe 'DELETE /projects/:id/repository/merged_branches' do
before do
allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true)
end
@@ -416,13 +509,14 @@ describe API::Branches do
it 'returns 202 with json body' do
delete api("/projects/#{project.id}/repository/merged_branches", user)
- expect(response).to have_http_status(202)
+ expect(response).to have_gitlab_http_status(202)
expect(json_response['message']).to eql('202 Accepted')
end
it 'returns a 403 error if guest' do
delete api("/projects/#{project.id}/repository/merged_branches", guest)
- expect(response).to have_http_status(403)
+
+ expect(response).to have_gitlab_http_status(403)
end
end
end
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index b8ca73c321c..8b62aa268d9 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -164,25 +164,40 @@ describe API::CommitStatuses do
context 'with all optional parameters' do
context 'when creating a commit status' do
- it 'creates commit status' do
+ subject do
post api(post_url, developer), {
state: 'success',
context: 'coverage',
- ref: 'develop',
+ ref: 'master',
description: 'test',
coverage: 80.0,
target_url: 'http://gitlab.com/status'
}
+ end
+
+ it 'creates commit status' do
+ subject
expect(response).to have_http_status(201)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
expect(json_response['name']).to eq('coverage')
- expect(json_response['ref']).to eq('develop')
+ expect(json_response['ref']).to eq('master')
expect(json_response['coverage']).to eq(80.0)
expect(json_response['description']).to eq('test')
expect(json_response['target_url']).to eq('http://gitlab.com/status')
end
+
+ context 'when merge request exists for given branch' do
+ let!(:merge_request) { create(:merge_request, source_project: project, source_branch: 'master', target_branch: 'develop') }
+
+ it 'sets head pipeline' do
+ subject
+
+ expect(response).to have_http_status(201)
+ expect(merge_request.reload.head_pipeline).not_to be_nil
+ end
+ end
end
context 'when updatig a commit status' do
@@ -190,7 +205,7 @@ describe API::CommitStatuses do
post api(post_url, developer), {
state: 'running',
context: 'coverage',
- ref: 'develop',
+ ref: 'master',
description: 'coverage test',
coverage: 0.0,
target_url: 'http://gitlab.com/status'
@@ -199,7 +214,7 @@ describe API::CommitStatuses do
post api(post_url, developer), {
state: 'success',
name: 'coverage',
- ref: 'develop',
+ ref: 'master',
description: 'new description',
coverage: 90.0
}
@@ -210,7 +225,7 @@ describe API::CommitStatuses do
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
expect(json_response['name']).to eq('coverage')
- expect(json_response['ref']).to eq('develop')
+ expect(json_response['ref']).to eq('master')
expect(json_response['coverage']).to eq(90.0)
expect(json_response['description']).to eq('new description')
expect(json_response['target_url']).to eq('http://gitlab.com/status')
@@ -222,6 +237,28 @@ describe API::CommitStatuses do
end
end
+ context 'when retrying a commit status' do
+ before do
+ post api(post_url, developer),
+ { state: 'failed', name: 'test', ref: 'master' }
+
+ post api(post_url, developer),
+ { state: 'success', name: 'test', ref: 'master' }
+ end
+
+ it 'correctly posts a new commit status' do
+ expect(response).to have_http_status(201)
+ expect(json_response['sha']).to eq(commit.id)
+ expect(json_response['status']).to eq('success')
+ end
+
+ it 'retries a commit status' do
+ expect(CommitStatus.count).to eq 2
+ expect(CommitStatus.first).to be_retried
+ expect(CommitStatus.last.pipeline).to be_success
+ end
+ end
+
context 'when status is invalid' do
before do
post api(post_url, developer), state: 'invalid'
diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb
index a19870a95e8..1754ba66a96 100644
--- a/spec/requests/api/events_spec.rb
+++ b/spec/requests/api/events_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::Events, api: true do
+describe API::Events do
include ApiHelpers
let(:user) { create(:user) }
let(:non_member) { create(:user) }
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
index f169e6661d1..7e21006b254 100644
--- a/spec/requests/api/features_spec.rb
+++ b/spec/requests/api/features_spec.rb
@@ -4,6 +4,13 @@ describe API::Features do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
+ before do
+ Flipper.unregister_groups
+ Flipper.register(:perf_team) do |actor|
+ actor.respond_to?(:admin) && actor.admin?
+ end
+ end
+
describe 'GET /features' do
let(:expected_features) do
[
@@ -16,6 +23,14 @@ describe API::Features do
'name' => 'feature_2',
'state' => 'off',
'gates' => [{ 'key' => 'boolean', 'value' => false }]
+ },
+ {
+ 'name' => 'feature_3',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'groups', 'value' => ['perf_team'] }
+ ]
}
]
end
@@ -23,6 +38,7 @@ describe API::Features do
before do
Feature.get('feature_1').enable
Feature.get('feature_2').disable
+ Feature.get('feature_3').enable Feature.group(:perf_team)
end
it 'returns a 401 for anonymous users' do
@@ -47,30 +63,84 @@ describe API::Features do
describe 'POST /feature' do
let(:feature_name) { 'my_feature' }
- it 'returns a 401 for anonymous users' do
- post api("/features/#{feature_name}")
- expect(response).to have_http_status(401)
- end
+ context 'when the feature does not exist' do
+ it 'returns a 401 for anonymous users' do
+ post api("/features/#{feature_name}")
- it 'returns a 403 for users' do
- post api("/features/#{feature_name}", user)
+ expect(response).to have_http_status(401)
+ end
- expect(response).to have_http_status(403)
- end
+ it 'returns a 403 for users' do
+ post api("/features/#{feature_name}", user)
- it 'creates an enabled feature if passed true' do
- post api("/features/#{feature_name}", admin), value: 'true'
+ expect(response).to have_http_status(403)
+ end
- expect(response).to have_http_status(201)
- expect(Feature.get(feature_name)).to be_enabled
- end
+ context 'when passed value=true' do
+ it 'creates an enabled feature' do
+ post api("/features/#{feature_name}", admin), value: 'true'
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'on',
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }])
+ end
+
+ it 'creates an enabled feature for the given Flipper group when passed feature_group=perf_team' do
+ post api("/features/#{feature_name}", admin), value: 'true', feature_group: 'perf_team'
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'groups', 'value' => ['perf_team'] }
+ ])
+ end
+
+ it 'creates an enabled feature for the given user when passed user=username' do
+ post api("/features/#{feature_name}", admin), value: 'true', user: user.username
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'actors', 'value' => ["User:#{user.id}"] }
+ ])
+ end
+
+ it 'creates an enabled feature for the given user and feature group when passed user=username and feature_group=perf_team' do
+ post api("/features/#{feature_name}", admin), value: 'true', user: user.username, feature_group: 'perf_team'
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'groups', 'value' => ['perf_team'] },
+ { 'key' => 'actors', 'value' => ["User:#{user.id}"] }
+ ])
+ end
+ end
- it 'creates a feature with the given percentage if passed an integer' do
- post api("/features/#{feature_name}", admin), value: '50'
+ it 'creates a feature with the given percentage if passed an integer' do
+ post api("/features/#{feature_name}", admin), value: '50'
- expect(response).to have_http_status(201)
- expect(Feature.get(feature_name).percentage_of_time_value).to be(50)
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'percentage_of_time', 'value' => 50 }
+ ])
+ end
end
context 'when the feature exists' do
@@ -80,11 +150,83 @@ describe API::Features do
feature.disable # This also persists the feature on the DB
end
- it 'enables the feature if passed true' do
- post api("/features/#{feature_name}", admin), value: 'true'
+ context 'when passed value=true' do
+ it 'enables the feature' do
+ post api("/features/#{feature_name}", admin), value: 'true'
- expect(response).to have_http_status(201)
- expect(feature).to be_enabled
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'on',
+ 'gates' => [{ 'key' => 'boolean', 'value' => true }])
+ end
+
+ it 'enables the feature for the given Flipper group when passed feature_group=perf_team' do
+ post api("/features/#{feature_name}", admin), value: 'true', feature_group: 'perf_team'
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'groups', 'value' => ['perf_team'] }
+ ])
+ end
+
+ it 'enables the feature for the given user when passed user=username' do
+ post api("/features/#{feature_name}", admin), value: 'true', user: user.username
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'actors', 'value' => ["User:#{user.id}"] }
+ ])
+ end
+ end
+
+ context 'when feature is enabled and value=false is passed' do
+ it 'disables the feature' do
+ feature.enable
+ expect(feature).to be_enabled
+
+ post api("/features/#{feature_name}", admin), value: 'false'
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'off',
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }])
+ end
+
+ it 'disables the feature for the given Flipper group when passed feature_group=perf_team' do
+ feature.enable(Feature.group(:perf_team))
+ expect(Feature.get(feature_name).enabled?(admin)).to be_truthy
+
+ post api("/features/#{feature_name}", admin), value: 'false', feature_group: 'perf_team'
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'off',
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }])
+ end
+
+ it 'disables the feature for the given user when passed user=username' do
+ feature.enable(user)
+ expect(Feature.get(feature_name).enabled?(user)).to be_truthy
+
+ post api("/features/#{feature_name}", admin), value: 'false', user: user.username
+
+ expect(response).to have_http_status(201)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'off',
+ 'gates' => [{ 'key' => 'boolean', 'value' => false }])
+ end
end
context 'with a pre-existing percentage value' do
@@ -96,7 +238,13 @@ describe API::Features do
post api("/features/#{feature_name}", admin), value: '30'
expect(response).to have_http_status(201)
- expect(Feature.get(feature_name).percentage_of_time_value).to be(30)
+ expect(json_response).to eq(
+ 'name' => 'my_feature',
+ 'state' => 'conditional',
+ 'gates' => [
+ { 'key' => 'boolean', 'value' => false },
+ { 'key' => 'percentage_of_time', 'value' => 30 }
+ ])
end
end
end
diff --git a/spec/requests/api/group_milestones_spec.rb b/spec/requests/api/group_milestones_spec.rb
new file mode 100644
index 00000000000..9b24658771f
--- /dev/null
+++ b/spec/requests/api/group_milestones_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe API::GroupMilestones do
+ let(:user) { create(:user) }
+ let(:group) { create(:group, :private) }
+ let(:project) { create(:empty_project, namespace: group) }
+ let!(:group_member) { create(:group_member, group: group, user: user) }
+ let!(:closed_milestone) { create(:closed_milestone, group: group, title: 'version1', description: 'closed milestone') }
+ let!(:milestone) { create(:milestone, group: group, title: 'version2', description: 'open milestone') }
+
+ it_behaves_like 'group and project milestones', "/groups/:id/milestones" do
+ let(:route) { "/groups/#{group.id}/milestones" }
+ end
+
+ def setup_for_group
+ context_group.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ context_group.add_developer(user)
+ public_project.update(namespace: context_group)
+ context_group.reload
+ end
+end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 656f098aea8..1d7adc6ac45 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -510,7 +510,7 @@ describe API::Groups do
describe "POST /groups/:id/projects/:project_id" do
let(:project) { create(:empty_project) }
- let(:project_path) { project.full_path.gsub('/', '%2F') }
+ let(:project_path) { CGI.escape(project.full_path) }
before(:each) do
allow_any_instance_of(Projects::TransferService)
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 191c60aba31..7a1bd76af7a 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -10,10 +10,22 @@ describe API::Helpers do
let(:key) { create(:key, user: user) }
let(:params) { {} }
- let(:env) { { 'REQUEST_METHOD' => 'GET' } }
- let(:request) { Rack::Request.new(env) }
+ let(:csrf_token) { SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) }
+ let(:env) do
+ {
+ 'rack.input' => '',
+ 'rack.session' => {
+ _csrf_token: csrf_token
+ },
+ 'REQUEST_METHOD' => 'GET'
+ }
+ end
let(:header) { }
+ before do
+ allow_any_instance_of(self.class).to receive(:options).and_return({})
+ end
+
def set_env(user_or_token, identifier)
clear_env
clear_param
@@ -54,7 +66,7 @@ describe API::Helpers do
describe ".current_user" do
subject { current_user }
- describe "Warden authentication" do
+ describe "Warden authentication", :allow_forgery_protection do
before do
doorkeeper_guard_returns false
end
@@ -95,7 +107,17 @@ describe API::Helpers do
env['REQUEST_METHOD'] = 'PUT'
end
- it { is_expected.to be_nil }
+ context 'without CSRF token' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with CSRF token' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = csrf_token
+ end
+
+ it { is_expected.to eq(user) }
+ end
end
context "POST request" do
@@ -103,7 +125,17 @@ describe API::Helpers do
env['REQUEST_METHOD'] = 'POST'
end
- it { is_expected.to be_nil }
+ context 'without CSRF token' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with CSRF token' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = csrf_token
+ end
+
+ it { is_expected.to eq(user) }
+ end
end
context "DELETE request" do
@@ -111,7 +143,17 @@ describe API::Helpers do
env['REQUEST_METHOD'] = 'DELETE'
end
- it { is_expected.to be_nil }
+ context 'without CSRF token' do
+ it { is_expected.to be_nil }
+ end
+
+ context 'with CSRF token' do
+ before do
+ env['HTTP_X_CSRF_TOKEN'] = csrf_token
+ end
+
+ it { is_expected.to eq(user) }
+ end
end
end
end
@@ -167,7 +209,6 @@ describe API::Helpers do
it "returns nil for a token without the appropriate scope" do
personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
env[API::APIGuard::PRIVATE_TOKEN_HEADER] = personal_access_token.token
- allow_access_with_scope('write_user')
expect(current_user).to be_nil
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 6deaea956e0..ce9b9ac1eb3 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -6,7 +6,7 @@ describe API::Internal do
let(:project) { create(:project, :repository) }
let(:secret_token) { Gitlab::Shell.secret_token }
- describe "GET /internal/check", no_db: true do
+ describe "GET /internal/check" do
it do
get api("/internal/check"), secret_token: secret_token
@@ -35,6 +35,17 @@ describe API::Internal do
expect(json_response).to be_empty
end
end
+
+ context 'nil broadcast message' do
+ it 'returns nothing' do
+ allow(BroadcastMessage).to receive(:current).and_return(nil)
+
+ get api('/internal/broadcast_message'), secret_token: secret_token
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_empty
+ end
+ end
end
describe 'GET /internal/broadcast_messages' do
@@ -168,7 +179,7 @@ describe API::Internal do
end
end
- describe "POST /internal/allowed", :redis do
+ describe "POST /internal/allowed", :clean_gitlab_redis_shared_state do
context "access granted" do
before do
project.team << [user, :developer]
@@ -220,26 +231,72 @@ describe API::Internal do
end
context "git pull" do
- it do
- pull(key, project)
+ context "gitaly disabled" do
+ it "has the correct payload" do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:ssh_upload_pack).and_return(false)
+ pull(key, project)
- expect(response).to have_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- expect(user).to have_an_activity_record
+ expect(response).to have_http_status(200)
+ expect(json_response["status"]).to be_truthy
+ expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
+ expect(json_response["gl_repository"]).to eq("project-#{project.id}")
+ expect(json_response["gitaly"]).to be_nil
+ expect(user).to have_an_activity_record
+ end
+ end
+
+ context "gitaly enabled" do
+ it "has the correct payload" do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:ssh_upload_pack).and_return(true)
+ pull(key, project)
+
+ expect(response).to have_http_status(200)
+ expect(json_response["status"]).to be_truthy
+ expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
+ expect(json_response["gl_repository"]).to eq("project-#{project.id}")
+ expect(json_response["gitaly"]).not_to be_nil
+ expect(json_response["gitaly"]["repository"]).not_to be_nil
+ expect(json_response["gitaly"]["repository"]["storage_name"]).to eq(project.repository.gitaly_repository.storage_name)
+ expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
+ expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
+ expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
+ expect(user).to have_an_activity_record
+ end
end
end
context "git push" do
- it do
- push(key, project)
+ context "gitaly disabled" do
+ it "has the correct payload" do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:ssh_receive_pack).and_return(false)
+ push(key, project)
- expect(response).to have_http_status(200)
- expect(json_response["status"]).to be_truthy
- expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
- expect(json_response["gl_repository"]).to eq("project-#{project.id}")
- expect(user).not_to have_an_activity_record
+ expect(response).to have_http_status(200)
+ expect(json_response["status"]).to be_truthy
+ expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
+ expect(json_response["gl_repository"]).to eq("project-#{project.id}")
+ expect(json_response["gitaly"]).to be_nil
+ expect(user).not_to have_an_activity_record
+ end
+ end
+
+ context "gitaly enabled" do
+ it "has the correct payload" do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:ssh_receive_pack).and_return(true)
+ push(key, project)
+
+ expect(response).to have_http_status(200)
+ expect(json_response["status"]).to be_truthy
+ expect(json_response["repository_path"]).to eq(project.repository.path_to_repo)
+ expect(json_response["gl_repository"]).to eq("project-#{project.id}")
+ expect(json_response["gitaly"]).not_to be_nil
+ expect(json_response["gitaly"]["repository"]).not_to be_nil
+ expect(json_response["gitaly"]["repository"]["storage_name"]).to eq(project.repository.gitaly_repository.storage_name)
+ expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path)
+ expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage))
+ expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage))
+ expect(user).not_to have_an_activity_record
+ end
end
context 'project as /namespace/project' do
@@ -537,10 +594,10 @@ describe API::Internal do
# end
#
# it "calls the Gitaly client with the project's repository" do
- # expect(Gitlab::GitalyClient::Notifications).
+ # expect(Gitlab::GitalyClient::NotificationService).
# to receive(:new).with(gitlab_git_repository_with(path: project.repository.path)).
# and_call_original
- # expect_any_instance_of(Gitlab::GitalyClient::Notifications).
+ # expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
# to receive(:post_receive)
#
# post api("/internal/notify_post_receive"), valid_params
@@ -549,10 +606,10 @@ describe API::Internal do
# end
#
# it "calls the Gitaly client with the wiki's repository if it's a wiki" do
- # expect(Gitlab::GitalyClient::Notifications).
+ # expect(Gitlab::GitalyClient::NotificationService).
# to receive(:new).with(gitlab_git_repository_with(path: project.wiki.repository.path)).
# and_call_original
- # expect_any_instance_of(Gitlab::GitalyClient::Notifications).
+ # expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
# to receive(:post_receive)
#
# post api("/internal/notify_post_receive"), valid_wiki_params
@@ -561,7 +618,7 @@ describe API::Internal do
# end
#
# it "returns 500 if the gitaly call fails" do
- # expect_any_instance_of(Gitlab::GitalyClient::Notifications).
+ # expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
# to receive(:post_receive).and_raise(GRPC::Unavailable)
#
# post api("/internal/notify_post_receive"), valid_params
@@ -579,10 +636,10 @@ describe API::Internal do
# end
#
# it "calls the Gitaly client with the project's repository" do
- # expect(Gitlab::GitalyClient::Notifications).
+ # expect(Gitlab::GitalyClient::NotificationService).
# to receive(:new).with(gitlab_git_repository_with(path: project.repository.path)).
# and_call_original
- # expect_any_instance_of(Gitlab::GitalyClient::Notifications).
+ # expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
# to receive(:post_receive)
#
# post api("/internal/notify_post_receive"), valid_params
@@ -591,10 +648,10 @@ describe API::Internal do
# end
#
# it "calls the Gitaly client with the wiki's repository if it's a wiki" do
- # expect(Gitlab::GitalyClient::Notifications).
+ # expect(Gitlab::GitalyClient::NotificationService).
# to receive(:new).with(gitlab_git_repository_with(path: project.wiki.repository.path)).
# and_call_original
- # expect_any_instance_of(Gitlab::GitalyClient::Notifications).
+ # expect_any_instance_of(Gitlab::GitalyClient::NotificationService).
# to receive(:post_receive)
#
# post api("/internal/notify_post_receive"), valid_wiki_params
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 79cac721202..2c44be4e447 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -71,7 +71,6 @@ describe API::Issues do
expect(response).to have_http_status(401)
end
end
-
context "when authenticated" do
let(:first_issue) { json_response.first }
@@ -105,6 +104,42 @@ describe API::Issues do
expect(json_response.second['id']).to eq(closed_issue.id)
end
+ it 'returns issues assigned to me' do
+ issue2 = create(:issue, assignees: [user2], project: project)
+
+ get api('/issues', user2), scope: 'assigned-to-me'
+
+ expect_paginated_array_response(size: 1)
+ expect(first_issue['id']).to eq(issue2.id)
+ end
+
+ it 'returns issues authored by the given author id' do
+ issue2 = create(:issue, author: user2, project: project)
+
+ get api('/issues', user), author_id: user2.id, scope: 'all'
+
+ expect_paginated_array_response(size: 1)
+ expect(first_issue['id']).to eq(issue2.id)
+ end
+
+ it 'returns issues assigned to the given assignee id' do
+ issue2 = create(:issue, assignees: [user2], project: project)
+
+ get api('/issues', user), assignee_id: user2.id, scope: 'all'
+
+ expect_paginated_array_response(size: 1)
+ expect(first_issue['id']).to eq(issue2.id)
+ end
+
+ it 'returns issues authored by the given author id and assigned to the given assignee id' do
+ issue2 = create(:issue, author: user2, assignees: [user2], project: project)
+
+ get api('/issues', user), author_id: user2.id, assignee_id: user2.id, scope: 'all'
+
+ expect_paginated_array_response(size: 1)
+ expect(first_issue['id']).to eq(issue2.id)
+ end
+
it 'returns issues matching given search string for title' do
get api("/issues", user), search: issue.title
@@ -693,6 +728,19 @@ describe API::Issues do
expect(json_response['confidential']).to be_falsy
end
+ context 'links exposure' do
+ it 'exposes related resources full URIs' do
+ get api("/projects/#{project.id}/issues/#{issue.iid}", user)
+
+ links = json_response['_links']
+
+ expect(links['self']).to end_with("/api/v4/projects/#{project.id}/issues/#{issue.iid}")
+ expect(links['notes']).to end_with("/api/v4/projects/#{project.id}/issues/#{issue.iid}/notes")
+ expect(links['award_emoji']).to end_with("/api/v4/projects/#{project.id}/issues/#{issue.iid}/award_emoji")
+ expect(links['project']).to end_with("/api/v4/projects/#{project.id}")
+ end
+ end
+
it "returns a project issue by internal id" do
get api("/projects/#{project.id}/issues/#{issue.iid}", user)
@@ -772,7 +820,7 @@ describe API::Issues do
end
end
- context 'CE restrictions' do
+ context 'single assignee restrictions' do
it 'creates a new project issue with no more than one assignee' do
post api("/projects/#{project.id}/issues", user),
title: 'new issue', assignee_ids: [user2.id, guest.id]
@@ -1123,7 +1171,7 @@ describe API::Issues do
expect(json_response['assignees'].first['name']).to eq(user2.name)
end
- context 'CE restrictions' do
+ context 'single assignee restrictions' do
it 'updates an issue with several assignees but only one has been applied' do
put api("/projects/#{project.id}/issues/#{issue.iid}", user),
assignee_ids: [user2.id, guest.id]
@@ -1211,7 +1259,7 @@ describe API::Issues do
put api("/projects/#{project.id}/issues/#{closed_issue.iid}", user), state_event: 'reopen'
expect(response).to have_http_status(200)
- expect(json_response['state']).to eq 'reopened'
+ expect(json_response['state']).to eq 'opened'
end
context 'when an admin or owner makes the request' do
@@ -1462,6 +1510,25 @@ describe API::Issues do
end
end
+ describe "GET /projects/:id/issues/:issue_iid/user_agent_detail" do
+ let!(:user_agent_detail) { create(:user_agent_detail, subject: issue) }
+
+ it 'exposes known attributes' do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['user_agent']).to eq(user_agent_detail.user_agent)
+ expect(json_response['ip_address']).to eq(user_agent_detail.ip_address)
+ expect(json_response['akismet_submitted']).to eq(user_agent_detail.submitted)
+ end
+
+ it "returns unautorized for non-admin users" do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
def expect_paginated_array_response(size: nil)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 8d647eb1c7e..f56baf9663d 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::Jobs, :api do
+describe API::Jobs do
let!(:project) do
create(:project, :repository, public_builds: false)
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 4d0bd67c571..2760c4ffde2 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -16,12 +16,110 @@ describe API::MergeRequests do
let!(:label) do
create(:label, title: 'label', color: '#FFAABB', project: project)
end
+ let!(:label2) { create(:label, title: 'a-test', color: '#FFFFFF', project: project) }
let!(:label_link) { create(:label_link, label: label, target: merge_request) }
+ let!(:label_link2) { create(:label_link, label: label2, target: merge_request) }
+ let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request) }
+ let!(:upvote) { create(:award_emoji, :upvote, awardable: merge_request) }
before do
project.team << [user, :reporter]
end
+ describe 'GET /merge_requests' do
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ get api('/merge_requests')
+
+ expect(response).to have_http_status(401)
+ end
+ end
+
+ context 'when authenticated' do
+ let!(:project2) { create(:empty_project, :public, namespace: user.namespace) }
+ let!(:merge_request2) { create(:merge_request, :simple, author: user, assignee: user, source_project: project2, target_project: project2) }
+ let(:user2) { create(:user) }
+
+ it 'returns an array of all merge requests' do
+ get api('/merge_requests', user), scope: :all
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.map { |mr| mr['id'] })
+ .to contain_exactly(merge_request.id, merge_request_closed.id, merge_request_merged.id, merge_request2.id)
+ end
+
+ it 'does not return unauthorized merge requests' do
+ private_project = create(:empty_project, :private)
+ merge_request3 = create(:merge_request, :simple, source_project: private_project, target_project: private_project, source_branch: 'other-branch')
+
+ get api('/merge_requests', user), scope: :all
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.map { |mr| mr['id'] })
+ .not_to include(merge_request3.id)
+ end
+
+ it 'returns an array of merge requests created by current user if no scope is given' do
+ merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch')
+
+ get api('/merge_requests', user2)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(merge_request3.id)
+ end
+
+ it 'returns an array of merge requests authored by the given user' do
+ merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch')
+
+ get api('/merge_requests', user), author_id: user2.id, scope: :all
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(merge_request3.id)
+ end
+
+ it 'returns an array of merge requests assigned to the given user' do
+ merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch')
+
+ get api('/merge_requests', user), assignee_id: user2.id, scope: :all
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(merge_request3.id)
+ end
+
+ it 'returns an array of merge requests assigned to me' do
+ merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch')
+
+ get api('/merge_requests', user2), scope: 'assigned-to-me'
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(merge_request3.id)
+ end
+
+ it 'returns an array of merge requests created by me' do
+ merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch')
+
+ get api('/merge_requests', user2), scope: 'created-by-me'
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(merge_request3.id)
+ end
+ end
+ end
+
describe "GET /projects/:id/merge_requests" do
context "when unauthenticated" do
it "returns authentication error" do
@@ -32,6 +130,18 @@ describe API::MergeRequests do
end
context "when authenticated" do
+ it 'avoids N+1 queries' do
+ control_count = ActiveRecord::QueryRecorder.new do
+ get api("/projects/#{project.id}/merge_requests", user)
+ end.count
+
+ create(:merge_request, state: 'closed', milestone: milestone1, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time)
+
+ expect do
+ get api("/projects/#{project.id}/merge_requests", user)
+ end.not_to exceed_query_limit(control_count)
+ end
+
it "returns an array of all merge_requests" do
get api("/projects/#{project.id}/merge_requests", user)
@@ -44,12 +154,31 @@ describe API::MergeRequests do
expect(json_response.last['sha']).to eq(merge_request.diff_head_sha)
expect(json_response.last['merge_commit_sha']).to be_nil
expect(json_response.last['merge_commit_sha']).to eq(merge_request.merge_commit_sha)
+ expect(json_response.last['downvotes']).to eq(1)
+ expect(json_response.last['upvotes']).to eq(1)
+ expect(json_response.last['labels']).to eq([label2.title, label.title])
expect(json_response.first['title']).to eq(merge_request_merged.title)
expect(json_response.first['sha']).to eq(merge_request_merged.diff_head_sha)
expect(json_response.first['merge_commit_sha']).not_to be_nil
expect(json_response.first['merge_commit_sha']).to eq(merge_request_merged.merge_commit_sha)
end
+ it "returns an array of all merge_requests using simple mode" do
+ get api("/projects/#{project.id}/merge_requests?view=simple", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response.last.keys).to match_array(%w(id iid title web_url created_at description project_id state updated_at))
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(json_response.last['iid']).to eq(merge_request.iid)
+ expect(json_response.last['title']).to eq(merge_request.title)
+ expect(json_response.last).to have_key('web_url')
+ expect(json_response.first['iid']).to eq(merge_request_merged.iid)
+ expect(json_response.first['title']).to eq(merge_request_merged.title)
+ expect(json_response.first).to have_key('web_url')
+ end
+
it "returns an array of all merge_requests" do
get api("/projects/#{project.id}/merge_requests?state", user)
@@ -145,7 +274,7 @@ describe API::MergeRequests do
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
- expect(json_response.first['labels']).to eq([label.title])
+ expect(json_response.first['labels']).to eq([label2.title, label.title])
end
it 'returns an array of labeled merge requests where all labels match' do
@@ -236,8 +365,8 @@ describe API::MergeRequests do
expect(json_response['author']).to be_a Hash
expect(json_response['target_branch']).to eq(merge_request.target_branch)
expect(json_response['source_branch']).to eq(merge_request.source_branch)
- expect(json_response['upvotes']).to eq(0)
- expect(json_response['downvotes']).to eq(0)
+ expect(json_response['upvotes']).to eq(1)
+ expect(json_response['downvotes']).to eq(1)
expect(json_response['source_project_id']).to eq(merge_request.source_project.id)
expect(json_response['target_project_id']).to eq(merge_request.target_project.id)
expect(json_response['work_in_progress']).to be_falsy
@@ -759,18 +888,24 @@ describe API::MergeRequests do
it 'handles external issues' do
jira_project = create(:jira_project, :public, name: 'JIR_EXT1')
- issue = ExternalIssue.new("#{jira_project.name}-123", jira_project)
- merge_request = create(:merge_request, :simple, author: user, assignee: user, source_project: jira_project)
- merge_request.update_attribute(:description, "Closes #{issue.to_reference(jira_project)}")
+ ext_issue = ExternalIssue.new("#{jira_project.name}-123", jira_project)
+ issue = create(:issue, project: jira_project)
+ description = "Closes #{ext_issue.to_reference(jira_project)}\ncloses #{issue.to_reference}"
+ merge_request = create(:merge_request,
+ :simple, author: user, assignee: user, source_project: jira_project, description: description)
get api("/projects/#{jira_project.id}/merge_requests/#{merge_request.iid}/closes_issues", user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.length).to eq(1)
+ expect(json_response.length).to eq(2)
+ expect(json_response.second['title']).to eq(ext_issue.title)
+ expect(json_response.second['id']).to eq(ext_issue.id)
+ expect(json_response.second['confidential']).to be_nil
expect(json_response.first['title']).to eq(issue.title)
expect(json_response.first['id']).to eq(issue.id)
+ expect(json_response.first['confidential']).not_to be_nil
end
it 'returns 403 if the user has no access to the merge request' do
diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb
index 3bf16a3ae27..26cf653ca8e 100644
--- a/spec/requests/api/namespaces_spec.rb
+++ b/spec/requests/api/namespaces_spec.rb
@@ -15,6 +15,20 @@ describe API::Namespaces do
end
context "when authenticated as admin" do
+ it "returns correct attributes" do
+ get api("/namespaces", admin)
+
+ group_kind_json_response = json_response.find { |resource| resource['kind'] == 'group' }
+ user_kind_json_response = json_response.find { |resource| resource['kind'] == 'user' }
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(group_kind_json_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path',
+ 'parent_id', 'members_count_with_descendants')
+
+ expect(user_kind_json_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path', 'parent_id')
+ end
+
it "admin: returns an array of all namespaces" do
get api("/namespaces", admin)
@@ -37,6 +51,27 @@ describe API::Namespaces do
end
context "when authenticated as a regular user" do
+ it "returns correct attributes when user can admin group" do
+ group1.add_owner(user)
+
+ get api("/namespaces", user)
+
+ owned_group_response = json_response.find { |resource| resource['id'] == group1.id }
+
+ expect(owned_group_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path',
+ 'parent_id', 'members_count_with_descendants')
+ end
+
+ it "returns correct attributes when user cannot admin group" do
+ group1.add_guest(user)
+
+ get api("/namespaces", user)
+
+ guest_group_response = json_response.find { |resource| resource['id'] == group1.id }
+
+ expect(guest_group_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path', 'parent_id')
+ end
+
it "user: returns an array of namespaces" do
get api("/namespaces", user)
diff --git a/spec/requests/api/pipeline_schedules_spec.rb b/spec/requests/api/pipeline_schedules_spec.rb
index 85d11deb26f..b34555d2815 100644
--- a/spec/requests/api/pipeline_schedules_spec.rb
+++ b/spec/requests/api/pipeline_schedules_spec.rb
@@ -279,6 +279,8 @@ describe API::PipelineSchedules do
end
context 'authenticated user with invalid permissions' do
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: master) }
+
it 'does not delete pipeline_schedule' do
delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}", developer)
diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb
new file mode 100644
index 00000000000..fe8fdbfd7e4
--- /dev/null
+++ b/spec/requests/api/project_milestones_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe API::ProjectMilestones do
+ let(:user) { create(:user) }
+ let!(:project) { create(:empty_project, namespace: user.namespace ) }
+ let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
+ let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') }
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ it_behaves_like 'group and project milestones', "/projects/:id/milestones" do
+ let(:route) { "/projects/#{project.id}/milestones" }
+ end
+
+ describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do
+ it 'creates an activity event when an milestone is closed' do
+ expect(Event).to receive(:create)
+
+ put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
+ state_event: 'close'
+ end
+ end
+end
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 518639f45a2..f220972bae3 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -5,6 +5,26 @@ describe API::ProjectSnippets do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
+ describe "GET /projects/:project_id/snippets/:id/user_agent_detail" do
+ let(:snippet) { create(:project_snippet, :public, project: project) }
+ let!(:user_agent_detail) { create(:user_agent_detail, subject: snippet) }
+
+ it 'exposes known attributes' do
+ get api("/projects/#{project.id}/snippets/#{snippet.id}/user_agent_detail", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['user_agent']).to eq(user_agent_detail.user_agent)
+ expect(json_response['ip_address']).to eq(user_agent_detail.ip_address)
+ expect(json_response['akismet_submitted']).to eq(user_agent_detail.submitted)
+ end
+
+ it "returns unautorized for non-admin users" do
+ get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/user_agent_detail", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
describe 'GET /projects/:project_id/snippets/' do
let(:user) { create(:user) }
@@ -20,7 +40,7 @@ describe API::ProjectSnippets do
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.size).to eq(3)
- expect(json_response.map{ |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id)
+ expect(json_response.map { |snippet| snippet['id'] }).to include(public_snippet.id, internal_snippet.id, private_snippet.id)
expect(json_response.last).to have_key('web_url')
end
@@ -38,7 +58,7 @@ describe API::ProjectSnippets do
describe 'GET /projects/:project_id/snippets/:id' do
let(:user) { create(:user) }
- let(:snippet) { create(:project_snippet, :public, project: project) }
+ let(:snippet) { create(:project_snippet, :public, project: project) }
it 'returns snippet json' do
get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index fd7ff0b9cff..6ed68fcff09 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -52,6 +52,24 @@ describe API::Projects do
end
end
+ shared_examples_for 'projects response without N + 1 queries' do
+ it 'avoids N + 1 queries' do
+ control_count = ActiveRecord::QueryRecorder.new do
+ get api('/projects', current_user)
+ end.count
+
+ if defined?(additional_project)
+ additional_project
+ else
+ create(:empty_project, :public)
+ end
+
+ expect do
+ get api('/projects', current_user)
+ end.not_to exceed_query_limit(control_count + 8)
+ end
+ end
+
let!(:public_project) { create(:empty_project, :public, name: 'public_project') }
before do
project
@@ -62,9 +80,13 @@ describe API::Projects do
context 'when unauthenticated' do
it_behaves_like 'projects response' do
- let(:filter) { {} }
+ let(:filter) { { search: project.name } }
+ let(:current_user) { user }
+ let(:projects) { [project] }
+ end
+
+ it_behaves_like 'projects response without N + 1 queries' do
let(:current_user) { nil }
- let(:projects) { [public_project] }
end
end
@@ -75,6 +97,21 @@ describe API::Projects do
let(:projects) { [public_project, project, project2, project3] }
end
+ it_behaves_like 'projects response without N + 1 queries' do
+ let(:current_user) { user }
+ end
+
+ context 'when some projects are in a group' do
+ before do
+ create(:empty_project, :public, group: create(:group))
+ end
+
+ it_behaves_like 'projects response without N + 1 queries' do
+ let(:current_user) { user }
+ let(:additional_project) { create(:empty_project, :public, group: create(:group)) }
+ end
+ end
+
it 'includes the project labels as the tag_list' do
get api('/projects', user)
@@ -122,6 +159,31 @@ describe API::Projects do
expect(json_response.first).to include 'statistics'
end
+ context 'when external issue tracker is enabled' do
+ let!(:jira_service) { create(:jira_service, project: project) }
+
+ it 'includes open_issues_count' do
+ get api('/projects', user)
+
+ expect(response.status).to eq 200
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first.keys).to include('open_issues_count')
+ expect(json_response.find { |hash| hash['id'] == project.id }.keys).to include('open_issues_count')
+ end
+
+ it 'does not include open_issues_count if issues are disabled' do
+ project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
+
+ get api('/projects', user)
+
+ expect(response.status).to eq 200
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.find { |hash| hash['id'] == project.id }.keys).not_to include('open_issues_count')
+ end
+ end
+
context 'and with simple=true' do
it 'returns a simplified version of all the projects' do
expected_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace)
@@ -347,7 +409,8 @@ describe API::Projects do
wiki_enabled: false,
only_allow_merge_if_pipeline_succeeds: false,
request_access_enabled: true,
- only_allow_merge_if_all_discussions_are_resolved: false
+ only_allow_merge_if_all_discussions_are_resolved: false,
+ ci_config_path: 'a/custom/path'
})
post api('/projects', user), project
@@ -404,7 +467,7 @@ describe API::Projects do
post api('/projects', user), project
project_id = json_response['id']
- expect(json_response['avatar_url']).to eq("http://localhost/uploads/system/project/avatar/#{project_id}/banana_sample.gif")
+ expect(json_response['avatar_url']).to eq("http://localhost/uploads/-/system/project/avatar/#{project_id}/banana_sample.gif")
end
it 'sets a project as allowing merge even if build fails' do
@@ -475,6 +538,26 @@ describe API::Projects do
end
end
+ describe 'GET /users/:user_id/projects/' do
+ let!(:public_project) { create(:empty_project, :public, name: 'public_project', creator_id: user4.id, namespace: user4.namespace) }
+
+ it 'returns error when user not found' do
+ get api('/users/9999/projects/')
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+
+ it 'returns projects filtered by user' do
+ get api("/users/#{user4.id}/projects/", user)
+
+ expect(response).to have_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id)
+ end
+ end
+
describe 'POST /projects/user/:id' do
before do
expect(project).to be_persisted
@@ -653,6 +736,7 @@ describe API::Projects do
expect(json_response['star_count']).to be_present
expect(json_response['forks_count']).to be_present
expect(json_response['public_jobs']).to be_present
+ expect(json_response['ci_config_path']).to be_nil
expect(json_response['shared_with_groups']).to be_an Array
expect(json_response['shared_with_groups'].length).to eq(1)
expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id)
@@ -684,7 +768,7 @@ describe API::Projects do
dot_user = create(:user, username: 'dot.user')
project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace)
- get api("/projects/#{dot_user.namespace.name}%2F#{project.path}", dot_user)
+ get api("/projects/#{CGI.escape(project.full_path)}", dot_user)
expect(response).to have_http_status(200)
expect(json_response['name']).to eq(project.name)
end
@@ -698,7 +782,8 @@ describe API::Projects do
'name' => user.namespace.name,
'path' => user.namespace.path,
'kind' => user.namespace.kind,
- 'full_path' => user.namespace.full_path
+ 'full_path' => user.namespace.full_path,
+ 'parent_id' => nil
})
end
@@ -730,6 +815,38 @@ describe API::Projects do
expect(json_response).not_to include("import_error")
end
+ context 'links exposure' do
+ it 'exposes related resources full URIs' do
+ get api("/projects/#{project.id}", user)
+
+ links = json_response['_links']
+
+ expect(links['self']).to end_with("/api/v4/projects/#{project.id}")
+ expect(links['issues']).to end_with("/api/v4/projects/#{project.id}/issues")
+ expect(links['merge_requests']).to end_with("/api/v4/projects/#{project.id}/merge_requests")
+ expect(links['repo_branches']).to end_with("/api/v4/projects/#{project.id}/repository/branches")
+ expect(links['labels']).to end_with("/api/v4/projects/#{project.id}/labels")
+ expect(links['events']).to end_with("/api/v4/projects/#{project.id}/events")
+ expect(links['members']).to end_with("/api/v4/projects/#{project.id}/members")
+ end
+
+ it 'filters related URIs when their feature is not enabled' do
+ project = create(:empty_project, :public,
+ :merge_requests_disabled,
+ :issues_disabled,
+ creator_id: user.id,
+ namespace: user.namespace)
+
+ get api("/projects/#{project.id}", user)
+
+ links = json_response['_links']
+
+ expect(links.has_key?('merge_requests')).to be_falsy
+ expect(links.has_key?('issues')).to be_falsy
+ expect(links['self']).to end_with("/api/v4/projects/#{project.id}")
+ end
+ end
+
describe 'permissions' do
context 'all projects' do
before do
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 339a57a1f20..ca5d98c78ef 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -351,7 +351,8 @@ describe API::Runner do
let(:expected_cache) do
[{ 'key' => 'cache_key',
'untracked' => false,
- 'paths' => ['vendor/*'] }]
+ 'paths' => ['vendor/*'],
+ 'policy' => 'pull-push' }]
end
it 'picks a job' do
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index ede48b1c888..c3ed5cd8ece 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -10,8 +10,8 @@ describe API::Settings, 'Settings' do
expect(response).to have_http_status(200)
expect(json_response).to be_an Hash
expect(json_response['default_projects_limit']).to eq(42)
- expect(json_response['signin_enabled']).to be_truthy
- expect(json_response['repository_storage']).to eq('default')
+ expect(json_response['password_authentication_enabled']).to be_truthy
+ expect(json_response['repository_storages']).to eq(['default'])
expect(json_response['koding_enabled']).to be_falsey
expect(json_response['koding_url']).to be_nil
expect(json_response['plantuml_enabled']).to be_falsey
@@ -32,8 +32,8 @@ describe API::Settings, 'Settings' do
it "updates application settings" do
put api("/application/settings", admin),
default_projects_limit: 3,
- signin_enabled: false,
- repository_storage: 'custom',
+ password_authentication_enabled: false,
+ repository_storages: ['custom'],
koding_enabled: true,
koding_url: 'http://koding.example.com',
plantuml_enabled: true,
@@ -46,8 +46,7 @@ describe API::Settings, 'Settings' do
help_page_support_url: 'http://example.com/help'
expect(response).to have_http_status(200)
expect(json_response['default_projects_limit']).to eq(3)
- expect(json_response['signin_enabled']).to be_falsey
- expect(json_response['repository_storage']).to eq('custom')
+ expect(json_response['password_authentication_enabled']).to be_falsey
expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['koding_enabled']).to be_truthy
expect(json_response['koding_url']).to eq('http://koding.example.com')
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index b20a187acfe..373fab4d98a 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -271,4 +271,25 @@ describe API::Snippets do
expect(json_response['message']).to eq('404 Snippet Not Found')
end
end
+
+ describe "GET /snippets/:id/user_agent_detail" do
+ let(:admin) { create(:admin) }
+ let(:snippet) { create(:personal_snippet, :public, author: user) }
+ let!(:user_agent_detail) { create(:user_agent_detail, subject: snippet) }
+
+ it 'exposes known attributes' do
+ get api("/snippets/#{snippet.id}/user_agent_detail", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['user_agent']).to eq(user_agent_detail.user_agent)
+ expect(json_response['ip_address']).to eq(user_agent_detail.ip_address)
+ expect(json_response['akismet_submitted']).to eq(user_agent_detail.submitted)
+ end
+
+ it "returns unautorized for non-admin users" do
+ get api("/snippets/#{snippet.id}/user_agent_detail", user)
+
+ expect(response).to have_http_status(403)
+ end
+ end
end
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 92533f4dfea..9fc73c6e092 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe API::Todos do
- let(:project_1) { create(:empty_project, :test_repo) }
+ let(:project_1) { create(:project) }
let(:project_2) { create(:empty_project) }
let(:author_1) { create(:user) }
let(:author_2) { create(:user) }
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
index 16ddade27d9..153596c2975 100644
--- a/spec/requests/api/triggers_spec.rb
+++ b/spec/requests/api/triggers_spec.rb
@@ -22,6 +22,7 @@ describe API::Triggers do
before do
stub_ci_pipeline_to_return_yaml_file
+ trigger.update(owner: user)
end
context 'Handles errors' do
@@ -36,12 +37,6 @@ describe API::Triggers do
expect(response).to have_http_status(404)
end
-
- it 'returns unauthorized if token is for different project' do
- post api("/projects/#{project2.id}/trigger/pipeline"), options.merge(ref: 'master')
-
- expect(response).to have_http_status(401)
- end
end
context 'Have a commit' do
@@ -61,7 +56,7 @@ describe API::Triggers do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch')
expect(response).to have_http_status(400)
- expect(json_response['message']).to eq('No pipeline created')
+ expect(json_response['message']).to eq('base' => ["Reference not found"])
end
context 'Validates variables' do
@@ -87,12 +82,18 @@ describe API::Triggers do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(variables: variables, ref: 'master')
expect(response).to have_http_status(201)
- expect(pipeline.builds.reload.first.trigger_request.variables).to eq(variables)
+ expect(pipeline.variables.map { |v| { v.key => v.value } }.last).to eq(variables)
end
end
end
context 'when triggering a pipeline from a trigger token' do
+ it 'does not leak the presence of project when token is for different project' do
+ post api("/projects/#{project2.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
+
+ expect(response).to have_http_status(404)
+ end
+
it 'creates builds from the ref given in the URL, not in the body' do
expect do
post api("/projects/#{project.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' }
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 18000d91795..66b165b438b 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -13,9 +13,40 @@ describe API::Users do
describe 'GET /users' do
context "when unauthenticated" do
- it "returns authentication error" do
+ it "returns authorization error when the `username` parameter is not passed" do
get api("/users")
- expect(response).to have_http_status(401)
+
+ expect(response).to have_http_status(403)
+ end
+
+ it "returns the user when a valid `username` parameter is passed" do
+ user = create(:user)
+
+ get api("/users"), username: user.username
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(1)
+ expect(json_response[0]['id']).to eq(user.id)
+ expect(json_response[0]['username']).to eq(user.username)
+ end
+
+ it "returns authorization error when the `username` parameter refers to an inaccessible user" do
+ user = create(:user)
+
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+
+ get api("/users"), username: user.username
+
+ expect(response).to have_http_status(403)
+ end
+
+ it "returns an empty response when an invalid `username` parameter is passed" do
+ get api("/users"), username: 'invalid'
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(0)
end
end
@@ -24,17 +55,22 @@ describe API::Users do
context "when public level is restricted" do
before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
- allow_any_instance_of(API::Helpers).to receive(:authenticate!).and_return(true)
end
- it "renders 403" do
- get api("/users")
- expect(response).to have_http_status(403)
+ context 'when authenticate as a regular user' do
+ it "renders 403" do
+ get api("/users", user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
end
- it "renders 404" do
- get api("/users/#{user.id}")
- expect(response).to have_http_status(404)
+ context 'when authenticate as an admin' do
+ it "renders 200" do
+ get api("/users", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ end
end
end
@@ -132,12 +168,42 @@ describe API::Users do
expect(response).to have_http_status(400)
end
+
+ it "returns a user created before a specific date" do
+ user = create(:user, created_at: Date.new(2000, 1, 1))
+
+ get api("/users?created_before=2000-01-02T00:00:00.060Z", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['username']).to eq(user.username)
+ end
+
+ it "returns no users created before a specific date" do
+ create(:user, created_at: Date.new(2001, 1, 1))
+
+ get api("/users?created_before=2000-01-02T00:00:00.060Z", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response.size).to eq(0)
+ end
+
+ it "returns users created before and after a specific date" do
+ user = create(:user, created_at: Date.new(2001, 1, 1))
+
+ get api("/users?created_before=2001-01-02T00:00:00.060Z&created_after=1999-01-02T00:00:00.060", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response.size).to eq(1)
+ expect(json_response.first['username']).to eq(user.username)
+ end
end
end
describe "GET /users/:id" do
it "returns a user by id" do
get api("/users/#{user.id}", user)
+
expect(response).to have_http_status(200)
expect(json_response['username']).to eq(user.username)
end
@@ -148,9 +214,22 @@ describe API::Users do
expect(json_response['is_admin']).to be_nil
end
- it "returns a 401 if unauthenticated" do
- get api("/users/9998")
- expect(response).to have_http_status(401)
+ context 'for an anonymous user' do
+ it "returns a user by id" do
+ get api("/users/#{user.id}")
+
+ expect(response).to have_http_status(200)
+ expect(json_response['username']).to eq(user.username)
+ end
+
+ it "returns a 404 if the target user is present but inaccessible" do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?).with(nil, :read_user, user).and_return(false)
+
+ get api("/users/#{user.id}")
+
+ expect(response).to have_http_status(404)
+ end
end
it "returns a 404 error if user id not found" do
@@ -345,6 +424,14 @@ describe API::Users do
expect(json_response['identities'].first['provider']).to eq('github')
end
end
+
+ context "scopes" do
+ let(:user) { admin }
+ let(:path) { '/users' }
+ let(:api_call) { method(:api) }
+
+ include_examples 'does not allow the "read_user" scope'
+ end
end
describe "GET /users/sign_up" do
@@ -364,6 +451,7 @@ describe API::Users do
it "updates user with new bio" do
put api("/users/#{user.id}", admin), { bio: 'new test bio' }
+
expect(response).to have_http_status(200)
expect(json_response['bio']).to eq('new test bio')
expect(user.reload.bio).to eq('new test bio')
@@ -396,13 +484,22 @@ describe API::Users do
it 'updates user with his own email' do
put api("/users/#{user.id}", admin), email: user.email
+
expect(response).to have_http_status(200)
expect(json_response['email']).to eq(user.email)
expect(user.reload.email).to eq(user.email)
end
+ it 'updates user with a new email' do
+ put api("/users/#{user.id}", admin), email: 'new@email.com'
+
+ expect(response).to have_http_status(200)
+ expect(user.reload.notification_email).to eq('new@email.com')
+ end
+
it 'updates user with his own username' do
put api("/users/#{user.id}", admin), username: user.username
+
expect(response).to have_http_status(200)
expect(json_response['username']).to eq(user.username)
expect(user.reload.username).to eq(user.username)
@@ -410,12 +507,14 @@ describe API::Users do
it "updates user's existing identity" do
put api("/users/#{omniauth_user.id}", admin), provider: 'ldapmain', extern_uid: '654321'
+
expect(response).to have_http_status(200)
expect(omniauth_user.reload.identities.first.extern_uid).to eq('654321')
end
it 'updates user with new identity' do
put api("/users/#{user.id}", admin), provider: 'github', extern_uid: 'john'
+
expect(response).to have_http_status(200)
expect(user.reload.identities.first.extern_uid).to eq('john')
expect(user.reload.identities.first.provider).to eq('github')
@@ -423,12 +522,14 @@ describe API::Users do
it "updates admin status" do
put api("/users/#{user.id}", admin), { admin: true }
+
expect(response).to have_http_status(200)
expect(user.reload.admin).to eq(true)
end
it "updates external status" do
put api("/users/#{user.id}", admin), { external: true }
+
expect(response.status).to eq 200
expect(json_response['external']).to eq(true)
expect(user.reload.external?).to be_truthy
@@ -436,6 +537,7 @@ describe API::Users do
it "does not update admin status" do
put api("/users/#{admin_user.id}", admin), { can_create_group: false }
+
expect(response).to have_http_status(200)
expect(admin_user.reload.admin).to eq(true)
expect(admin_user.can_create_group).to eq(false)
@@ -443,6 +545,7 @@ describe API::Users do
it "does not allow invalid update" do
put api("/users/#{user.id}", admin), { email: 'invalid email' }
+
expect(response).to have_http_status(400)
expect(user.reload.email).not_to eq('invalid email')
end
@@ -459,6 +562,7 @@ describe API::Users do
it "returns 404 for non-existing user" do
put api("/users/999999", admin), { bio: 'update should fail' }
+
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 User Not Found')
end
@@ -509,6 +613,7 @@ describe API::Users do
it 'returns 409 conflict error if email address exists' do
put api("/users/#{@user.id}", admin), email: 'test@example.com'
+
expect(response).to have_http_status(409)
expect(@user.reload.email).to eq(@user.email)
end
@@ -516,6 +621,7 @@ describe API::Users do
it 'returns 409 conflict error if username taken' do
@user_id = User.all.last.id
put api("/users/#{@user.id}", admin), username: 'test'
+
expect(response).to have_http_status(409)
expect(@user.reload.username).to eq(@user.username)
end
@@ -823,6 +929,13 @@ describe API::Users do
expect(response).to match_response_schema('public_api/v4/user/public')
expect(json_response['id']).to eq(user.id)
end
+
+ context "scopes" do
+ let(:path) { "/user" }
+ let(:api_call) { method(:api) }
+
+ include_examples 'allows the "read_user" scope'
+ end
end
context 'with admin' do
@@ -835,11 +948,11 @@ describe API::Users do
expect(response).to have_http_status(403)
end
- it 'returns initial current user without private token when sudo not defined' do
+ it 'returns initial current user without private token but with is_admin when sudo not defined' do
get api("/user?private_token=#{admin_personal_access_token}")
expect(response).to have_http_status(200)
- expect(response).to match_response_schema('public_api/v4/user/public')
+ expect(response).to match_response_schema('public_api/v4/user/admin')
expect(json_response['id']).to eq(admin.id)
end
end
@@ -853,11 +966,11 @@ describe API::Users do
expect(json_response['id']).to eq(user.id)
end
- it 'returns initial current user without private token when sudo not defined' do
+ it 'returns initial current user without private token but with is_admin when sudo not defined' do
get api("/user?private_token=#{admin.private_token}")
expect(response).to have_http_status(200)
- expect(response).to match_response_schema('public_api/v4/user/public')
+ expect(response).to match_response_schema('public_api/v4/user/admin')
expect(json_response['id']).to eq(admin.id)
end
end
@@ -892,6 +1005,13 @@ describe API::Users do
expect(json_response).to be_an Array
expect(json_response.first["title"]).to eq(key.title)
end
+
+ context "scopes" do
+ let(:path) { "/user/keys" }
+ let(:api_call) { method(:api) }
+
+ include_examples 'allows the "read_user" scope'
+ end
end
end
@@ -925,6 +1045,13 @@ describe API::Users do
expect(response).to have_http_status(404)
end
+
+ context "scopes" do
+ let(:path) { "/user/keys/#{key.id}" }
+ let(:api_call) { method(:api) }
+
+ include_examples 'allows the "read_user" scope'
+ end
end
describe "POST /user/keys" do
@@ -1014,6 +1141,13 @@ describe API::Users do
expect(json_response).to be_an Array
expect(json_response.first["email"]).to eq(email.email)
end
+
+ context "scopes" do
+ let(:path) { "/user/emails" }
+ let(:api_call) { method(:api) }
+
+ include_examples 'allows the "read_user" scope'
+ end
end
end
@@ -1046,6 +1180,13 @@ describe API::Users do
expect(response).to have_http_status(404)
end
+
+ context "scopes" do
+ let(:path) { "/user/emails/#{email.id}" }
+ let(:api_call) { method(:api) }
+
+ include_examples 'allows the "read_user" scope'
+ end
end
describe "POST /user/emails" do
@@ -1177,7 +1318,7 @@ describe API::Users do
end
end
- context "user activities", :redis do
+ context "user activities", :clean_gitlab_redis_shared_state do
let!(:old_active_user) { create(:user, last_activity_on: Time.utc(2000, 1, 1)) }
let!(:newly_active_user) { create(:user, last_activity_on: 2.days.ago.midday) }
diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb
index 63c5707b2e4..5cdc528e190 100644
--- a/spec/requests/api/v3/groups_spec.rb
+++ b/spec/requests/api/v3/groups_spec.rb
@@ -502,7 +502,7 @@ describe API::V3::Groups do
describe "POST /groups/:id/projects/:project_id" do
let(:project) { create(:empty_project) }
- let(:project_path) { "#{project.namespace.path}%2F#{project.path}" }
+ let(:project_path) { CGI.escape(project.full_path) }
before(:each) do
allow_any_instance_of(Projects::TransferService)
diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb
index cc81922697a..4dff09b6df8 100644
--- a/spec/requests/api/v3/issues_spec.rb
+++ b/spec/requests/api/v3/issues_spec.rb
@@ -1114,7 +1114,7 @@ describe API::V3::Issues do
put v3_api("/projects/#{project.id}/issues/#{closed_issue.id}", user), state_event: 'reopen'
expect(response).to have_http_status(200)
- expect(json_response['state']).to eq 'reopened'
+ expect(json_response['state']).to eq 'opened'
end
context 'when an admin or owner makes the request' do
diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb
index 1969d1c7f2b..b0eddbb5dd2 100644
--- a/spec/requests/api/v3/project_hooks_spec.rb
+++ b/spec/requests/api/v3/project_hooks_spec.rb
@@ -87,7 +87,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
it "adds hook to project" do
expect do
post v3_api("/projects/#{project.id}/hooks", user),
- url: "http://example.com", issues_events: true, wiki_page_events: true
+ url: "http://example.com", issues_events: true, wiki_page_events: true, build_events: true
end.to change {project.hooks.count}.by(1)
expect(response).to have_http_status(201)
@@ -97,7 +97,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
expect(json_response['merge_requests_events']).to eq(false)
expect(json_response['tag_push_events']).to eq(false)
expect(json_response['note_events']).to eq(false)
- expect(json_response['build_events']).to eq(false)
+ expect(json_response['build_events']).to eq(true)
expect(json_response['pipeline_events']).to eq(false)
expect(json_response['wiki_page_events']).to eq(true)
expect(json_response['enable_ssl_verification']).to eq(true)
@@ -135,7 +135,7 @@ describe API::ProjectHooks, 'ProjectHooks' do
describe "PUT /projects/:id/hooks/:hook_id" do
it "updates an existing project hook" do
put v3_api("/projects/#{project.id}/hooks/#{hook.id}", user),
- url: 'http://example.org', push_events: false
+ url: 'http://example.org', push_events: false, build_events: true
expect(response).to have_http_status(200)
expect(json_response['url']).to eq('http://example.org')
expect(json_response['issues_events']).to eq(hook.issues_events)
diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb
index af4b6f92b64..bbfcaab1ea1 100644
--- a/spec/requests/api/v3/projects_spec.rb
+++ b/spec/requests/api/v3/projects_spec.rb
@@ -124,6 +124,36 @@ describe API::V3::Projects do
end
end
+ context 'and using archived' do
+ let!(:archived_project) { create(:empty_project, creator_id: user.id, namespace: user.namespace, archived: true) }
+
+ it 'returns archived project' do
+ get v3_api('/projects?archived=true', user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(archived_project.id)
+ end
+
+ it 'returns non-archived project' do
+ get v3_api('/projects?archived=false', user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['id']).to eq(project.id)
+ end
+
+ it 'returns all project' do
+ get v3_api('/projects', user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ end
+ end
+
context 'and using sorting' do
before do
project2
@@ -690,7 +720,7 @@ describe API::V3::Projects do
dot_user = create(:user, username: 'dot.user')
project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace)
- get v3_api("/projects/#{dot_user.namespace.name}%2F#{project.path}", dot_user)
+ get v3_api("/projects/#{CGI.escape(project.full_path)}", dot_user)
expect(response).to have_http_status(200)
expect(json_response['name']).to eq(project.name)
end
@@ -704,7 +734,8 @@ describe API::V3::Projects do
'name' => user.namespace.name,
'path' => user.namespace.path,
'kind' => user.namespace.kind,
- 'full_path' => user.namespace.full_path
+ 'full_path' => user.namespace.full_path,
+ 'parent_id' => nil
})
end
diff --git a/spec/requests/api/v3/settings_spec.rb b/spec/requests/api/v3/settings_spec.rb
index 41d039b7da0..291f6dcc2aa 100644
--- a/spec/requests/api/v3/settings_spec.rb
+++ b/spec/requests/api/v3/settings_spec.rb
@@ -10,7 +10,7 @@ describe API::V3::Settings, 'Settings' do
expect(response).to have_http_status(200)
expect(json_response).to be_an Hash
expect(json_response['default_projects_limit']).to eq(42)
- expect(json_response['signin_enabled']).to be_truthy
+ expect(json_response['password_authentication_enabled']).to be_truthy
expect(json_response['repository_storage']).to eq('default')
expect(json_response['koding_enabled']).to be_falsey
expect(json_response['koding_url']).to be_nil
@@ -28,11 +28,11 @@ describe API::V3::Settings, 'Settings' do
it "updates application settings" do
put v3_api("/application/settings", admin),
- default_projects_limit: 3, signin_enabled: false, repository_storage: 'custom', koding_enabled: true, koding_url: 'http://koding.example.com',
+ default_projects_limit: 3, password_authentication_enabled: false, repository_storage: 'custom', koding_enabled: true, koding_url: 'http://koding.example.com',
plantuml_enabled: true, plantuml_url: 'http://plantuml.example.com'
expect(response).to have_http_status(200)
expect(json_response['default_projects_limit']).to eq(3)
- expect(json_response['signin_enabled']).to be_falsey
+ expect(json_response['password_authentication_enabled']).to be_falsey
expect(json_response['repository_storage']).to eq('custom')
expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['koding_enabled']).to be_truthy
diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb
index d3de6bf13bc..60212660fb6 100644
--- a/spec/requests/api/v3/triggers_spec.rb
+++ b/spec/requests/api/v3/triggers_spec.rb
@@ -52,7 +52,8 @@ describe API::V3::Triggers do
it 'returns bad request with no builds created if there\'s no commit for that ref' do
post v3_api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'other-branch')
expect(response).to have_http_status(400)
- expect(json_response['message']).to eq('No builds created')
+ expect(json_response['message']['base'])
+ .to contain_exactly('Reference not found')
end
context 'Validates variables' do
diff --git a/spec/requests/api/v3/users_spec.rb b/spec/requests/api/v3/users_spec.rb
index 6d7401f9764..de7499a4e43 100644
--- a/spec/requests/api/v3/users_spec.rb
+++ b/spec/requests/api/v3/users_spec.rb
@@ -67,6 +67,19 @@ describe API::V3::Users do
expect(json_response.first['title']).to eq(key.title)
end
end
+
+ context "scopes" do
+ let(:user) { admin }
+ let(:path) { "/users/#{user.id}/keys" }
+ let(:api_call) { method(:v3_api) }
+
+ before do
+ user.keys << key
+ user.save
+ end
+
+ include_examples 'allows the "read_user" scope'
+ end
end
describe 'GET /user/:id/emails' do
@@ -287,7 +300,7 @@ describe API::V3::Users do
end
it 'returns a 404 error if not found' do
- get v3_api('/users/42/events', user)
+ get v3_api('/users/420/events', user)
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 User Not Found')
@@ -312,5 +325,13 @@ describe API::V3::Users do
expect(json_response['is_admin']).to be_nil
end
+
+ context "scopes" do
+ let(:user) { admin }
+ let(:path) { '/users' }
+ let(:api_call) { method(:v3_api) }
+
+ include_examples 'does not allow the "read_user" scope'
+ end
end
end
diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb
index 83673864fe7..e0975024b80 100644
--- a/spec/requests/api/variables_spec.rb
+++ b/spec/requests/api/variables_spec.rb
@@ -82,6 +82,17 @@ describe API::Variables do
expect(json_response['protected']).to be_truthy
end
+ it 'creates variable with optional attributes' do
+ expect do
+ post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2'
+ end.to change{project.variables.count}.by(1)
+
+ expect(response).to have_http_status(201)
+ expect(json_response['key']).to eq('TEST_VARIABLE_2')
+ expect(json_response['value']).to eq('VALUE_2')
+ expect(json_response['protected']).to be_falsey
+ end
+
it 'does not allow to duplicate variable key' do
expect do
post api("/projects/#{project.id}/variables", user), key: variable.key, value: 'VALUE_2'
diff --git a/spec/requests/api/version_spec.rb b/spec/requests/api/version_spec.rb
index 8870d48bbc9..7bbf34422b8 100644
--- a/spec/requests/api/version_spec.rb
+++ b/spec/requests/api/version_spec.rb
@@ -6,7 +6,7 @@ describe API::Version do
it 'returns authentication error' do
get api('/version')
- expect(response).to have_http_status(401)
+ expect(response).to have_gitlab_http_status(401)
end
end
@@ -16,7 +16,7 @@ describe API::Version do
it 'returns the version information' do
get api('/version', user)
- expect(response).to have_http_status(200)
+ expect(response).to have_gitlab_http_status(200)
expect(json_response['version']).to eq(Gitlab::VERSION)
expect(json_response['revision']).to eq(Gitlab::REVISION)
end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index c969d08d0dd..49e815ee16c 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -69,6 +69,72 @@ describe Ci::API::Builds do
end
end
+ context 'when an old image syntax is used' do
+ before do
+ build.update!(options: { image: 'codeclimate' })
+ end
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response["options"]).to eq({ "image" => "codeclimate" })
+ end
+ end
+
+ context 'when a new image syntax is used' do
+ before do
+ build.update!(options: { image: { name: 'codeclimate' } })
+ end
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response["options"]).to eq({ "image" => "codeclimate" })
+ end
+ end
+
+ context 'when an old service syntax is used' do
+ before do
+ build.update!(options: { services: ['mysql'] })
+ end
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response["options"]).to eq({ "services" => ["mysql"] })
+ end
+ end
+
+ context 'when a new service syntax is used' do
+ before do
+ build.update!(options: { services: [name: 'mysql'] })
+ end
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response["options"]).to eq({ "services" => ["mysql"] })
+ end
+ end
+
+ context 'when no image or service is defined' do
+ before do
+ build.update!(options: {})
+ end
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+
+ expect(json_response["options"]).to be_empty
+ end
+ end
+
context 'when there is a pending build' do
it 'starts a build' do
register_builds info: { platform: :darwin }
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index 26b03c0f148..e481ca916ab 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -5,7 +5,14 @@ describe Ci::API::Triggers do
let!(:trigger_token) { 'secure token' }
let!(:project) { create(:project, :repository, ci_id: 10) }
let!(:project2) { create(:empty_project, ci_id: 11) }
- let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) }
+
+ let!(:trigger) do
+ create(:ci_trigger,
+ project: project,
+ token: trigger_token,
+ owner: create(:user))
+ end
+
let(:options) do
{
token: trigger_token
@@ -14,6 +21,8 @@ describe Ci::API::Triggers do
before do
stub_ci_pipeline_to_return_yaml_file
+
+ project.add_developer(trigger.owner)
end
context 'Handles errors' do
@@ -47,7 +56,8 @@ describe Ci::API::Triggers do
it 'returns bad request with no builds created if there\'s no commit for that ref' do
post ci_api("/projects/#{project.ci_id}/refs/other-branch/trigger"), options
expect(response).to have_http_status(400)
- expect(json_response['message']).to eq('No builds created')
+ expect(json_response['message']['base'])
+ .to contain_exactly('Reference not found')
end
context 'Validates variables' do
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 185679e1a0f..d4a3e8b13e1 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe 'Git HTTP requests', lib: true do
+describe 'Git HTTP requests' do
include GitHttpHelpers
include WorkhorseHelpers
include UserActivitiesHelpers
@@ -406,7 +406,7 @@ describe 'Git HTTP requests', lib: true do
end
end
- it 'updates the user last activity', :redis do
+ it 'updates the user last activity', :clean_gitlab_redis_shared_state do
expect(user_activity(user)).to be_nil
download(path, env) do |response|
@@ -463,7 +463,7 @@ describe 'Git HTTP requests', lib: true do
context 'when internal auth is disabled' do
before do
- allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false }
+ allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled?) { false }
end
it 'rejects pulls with personal access token error message' do
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index 5e4cf05748e..8d79ea3dd40 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -101,7 +101,7 @@ describe JwtController do
context 'when internal auth is disabled' do
it 'rejects the authorization attempt with personal access token message' do
- allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false }
+ allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled?) { false }
get '/jwt/auth', parameters, headers
expect(response).to have_http_status(401)
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 6d1f0b24196..a927de952d0 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -79,7 +79,7 @@ describe 'OpenID Connect requests' do
'email_verified' => true,
'website' => 'https://example.com',
'profile' => 'http://localhost/alice',
- 'picture' => "http://localhost/uploads/system/user/avatar/#{user.id}/dk.png"
+ 'picture' => "http://localhost/uploads/-/system/user/avatar/#{user.id}/dk.png"
})
end
end
@@ -98,7 +98,7 @@ describe 'OpenID Connect requests' do
expect(@payload['sub']).to eq hashed_subject
end
- it 'includes the time of the last authentication', :redis do
+ it 'includes the time of the last authentication', :clean_gitlab_redis_shared_state do
expect(@payload['auth_time']).to eq user.current_sign_in_at.to_i
end
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index d4d3c9478a0..e5d9d3df5a8 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'cycle analytics events', api: true do
+describe 'cycle analytics events' do
let(:user) { create(:user) }
let(:project) { create(:project, :repository, public_builds: false) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
@@ -21,7 +21,7 @@ describe 'cycle analytics events', api: true do
end
it 'lists the issue events' do
- get namespace_project_cycle_analytics_issue_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_issue_path(project, format: :json)
first_issue_iid = project.issues.sort(:created_desc).pluck(:iid).first.to_s
@@ -30,7 +30,7 @@ describe 'cycle analytics events', api: true do
end
it 'lists the plan events' do
- get namespace_project_cycle_analytics_plan_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_plan_path(project, format: :json)
first_mr_short_sha = project.merge_requests.sort(:created_asc).first.commits.first.short_id
@@ -39,7 +39,7 @@ describe 'cycle analytics events', api: true do
end
it 'lists the code events' do
- get namespace_project_cycle_analytics_code_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_code_path(project, format: :json)
expect(json_response['events']).not_to be_empty
@@ -49,14 +49,14 @@ describe 'cycle analytics events', api: true do
end
it 'lists the test events' do
- get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_test_path(project, format: :json)
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['date']).not_to be_empty
end
it 'lists the review events' do
- get namespace_project_cycle_analytics_review_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_review_path(project, format: :json)
first_mr_iid = project.merge_requests.sort(:created_desc).pluck(:iid).first.to_s
@@ -65,14 +65,14 @@ describe 'cycle analytics events', api: true do
end
it 'lists the staging events' do
- get namespace_project_cycle_analytics_staging_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_staging_path(project, format: :json)
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['date']).not_to be_empty
end
it 'lists the production events' do
- get namespace_project_cycle_analytics_production_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_production_path(project, format: :json)
first_issue_iid = project.issues.sort(:created_desc).pluck(:iid).first.to_s
@@ -84,7 +84,7 @@ describe 'cycle analytics events', api: true do
it 'lists the test events' do
branch = project.merge_requests.first.source_branch
- get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json, branch: branch)
+ get project_cycle_analytics_test_path(project, format: :json, branch: branch)
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['date']).not_to be_empty
@@ -97,19 +97,19 @@ describe 'cycle analytics events', api: true do
end
it 'does not list the test events' do
- get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_test_path(project, format: :json)
expect(response).to have_http_status(:not_found)
end
it 'does not list the staging events' do
- get namespace_project_cycle_analytics_staging_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_staging_path(project, format: :json)
expect(response).to have_http_status(:not_found)
end
it 'lists the issue events' do
- get namespace_project_cycle_analytics_issue_path(project.namespace, project, format: :json)
+ get project_cycle_analytics_issue_path(project, format: :json)
expect(response).to have_http_status(:ok)
end
diff --git a/spec/routing/environments_spec.rb b/spec/routing/environments_spec.rb
index 624f3c43f0a..9b70c2a24be 100644
--- a/spec/routing/environments_spec.rb
+++ b/spec/routing/environments_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'environments routing', :routing do
+describe 'environments routing' do
let(:project) { create(:empty_project) }
let(:environment) do
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 95d40138fea..c02409b2e0b 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -246,28 +246,13 @@ describe 'project routing' do
end
end
- # diffs_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/diffs(.:format) projects/merge_requests#diffs
- # commits_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/commits(.:format) projects/merge_requests#commits
- # merge_namespace_project_merge_request POST /:namespace_id/:project_id/merge_requests/:id/merge(.:format) projects/merge_requests#merge
- # ci_status_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/ci_status(.:format) projects/merge_requests#ci_status
- # toggle_subscription_namespace_project_merge_request POST /:namespace_id/:project_id/merge_requests/:id/toggle_subscription(.:format) projects/merge_requests#toggle_subscription
- # branch_from_namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests/branch_from(.:format) projects/merge_requests#branch_from
- # branch_to_namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests/branch_to(.:format) projects/merge_requests#branch_to
- # update_branches_namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests/update_branches(.:format) projects/merge_requests#update_branches
- # namespace_project_merge_requests GET /:namespace_id/:project_id/merge_requests(.:format) projects/merge_requests#index
- # POST /:namespace_id/:project_id/merge_requests(.:format) projects/merge_requests#create
- # new_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/new(.:format) projects/merge_requests#new
- # edit_namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id/edit(.:format) projects/merge_requests#edit
- # namespace_project_merge_request GET /:namespace_id/:project_id/merge_requests/:id(.:format) projects/merge_requests#show
- # PATCH /:namespace_id/:project_id/merge_requests/:id(.:format) projects/merge_requests#update
- # PUT /:namespace_id/:project_id/merge_requests/:id(.:format) projects/merge_requests#update
describe Projects::MergeRequestsController, 'routing' do
- it 'to #diffs' do
- expect(get('/gitlab/gitlabhq/merge_requests/1/diffs')).to route_to('projects/merge_requests#diffs', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
+ it 'to #commits' do
+ expect(get('/gitlab/gitlabhq/merge_requests/1/commits.json')).to route_to('projects/merge_requests#commits', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'json')
end
- it 'to #commits' do
- expect(get('/gitlab/gitlabhq/merge_requests/1/commits')).to route_to('projects/merge_requests#commits', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
+ it 'to #pipelines' do
+ expect(get('/gitlab/gitlabhq/merge_requests/1/pipelines.json')).to route_to('projects/merge_requests#pipelines', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'json')
end
it 'to #merge' do
@@ -277,25 +262,59 @@ describe 'project routing' do
)
end
+ it 'to #show' do
+ expect(get('/gitlab/gitlabhq/merge_requests/1.diff')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'diff')
+ expect(get('/gitlab/gitlabhq/merge_requests/1.patch')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'patch')
+ expect(get('/gitlab/gitlabhq/merge_requests/1/diffs')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', tab: 'diffs')
+ expect(get('/gitlab/gitlabhq/merge_requests/1/commits')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', tab: 'commits')
+ expect(get('/gitlab/gitlabhq/merge_requests/1/pipelines')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', tab: 'pipelines')
+ end
+
+ it_behaves_like 'RESTful project resources' do
+ let(:controller) { 'merge_requests' }
+ let(:actions) { [:index, :edit, :show, :update] }
+ end
+ end
+
+ describe Projects::MergeRequests::CreationsController, 'routing' do
+ it 'to #new' do
+ expect(get('/gitlab/gitlabhq/merge_requests/new')).to route_to('projects/merge_requests/creations#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(get('/gitlab/gitlabhq/merge_requests/new/diffs')).to route_to('projects/merge_requests/creations#new', namespace_id: 'gitlab', project_id: 'gitlabhq', tab: 'diffs')
+ expect(get('/gitlab/gitlabhq/merge_requests/new/pipelines')).to route_to('projects/merge_requests/creations#new', namespace_id: 'gitlab', project_id: 'gitlabhq', tab: 'pipelines')
+ end
+
+ it 'to #create' do
+ expect(post('/gitlab/gitlabhq/merge_requests')).to route_to('projects/merge_requests/creations#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ end
+
it 'to #branch_from' do
- expect(get('/gitlab/gitlabhq/merge_requests/branch_from')).to route_to('projects/merge_requests#branch_from', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(get('/gitlab/gitlabhq/merge_requests/new/branch_from')).to route_to('projects/merge_requests/creations#branch_from', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #branch_to' do
- expect(get('/gitlab/gitlabhq/merge_requests/branch_to')).to route_to('projects/merge_requests#branch_to', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(get('/gitlab/gitlabhq/merge_requests/new/branch_to')).to route_to('projects/merge_requests/creations#branch_to', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
- it 'to #show' do
- expect(get('/gitlab/gitlabhq/merge_requests/1.diff')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'diff')
- expect(get('/gitlab/gitlabhq/merge_requests/1.patch')).to route_to('projects/merge_requests#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'patch')
+ it 'to #pipelines' do
+ expect(get('/gitlab/gitlabhq/merge_requests/new/pipelines.json')).to route_to('projects/merge_requests/creations#pipelines', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'json')
end
- it_behaves_like 'RESTful project resources' do
- let(:controller) { 'merge_requests' }
- let(:actions) { [:index, :create, :new, :edit, :show, :update] }
+ it 'to #diffs' do
+ expect(get('/gitlab/gitlabhq/merge_requests/new/diffs.json')).to route_to('projects/merge_requests/creations#diffs', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'json')
+ end
+ end
+
+ describe Projects::MergeRequests::DiffsController, 'routing' do
+ it 'to #show' do
+ expect(get('/gitlab/gitlabhq/merge_requests/1/diffs.json')).to route_to('projects/merge_requests/diffs#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: 'json')
end
end
+ describe Projects::MergeRequests::ConflictsController, 'routing' do
+ it 'to #show' do
+ expect(get('/gitlab/gitlabhq/merge_requests/1/conflicts')).to route_to('projects/merge_requests/conflicts#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
+ end
+ end
# raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw
# project_snippets GET /:project_id/snippets(.:format) snippets#index
# POST /:project_id/snippets(.:format) snippets#create
@@ -590,4 +609,26 @@ describe 'project routing' do
expect(get('/gitlab/gitlabhq/pages/domains/my.domain.com')).to route_to('projects/pages_domains#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'my.domain.com')
end
end
+
+ describe Projects::Registry::TagsController, 'routing' do
+ describe '#destroy' do
+ it 'correctly routes to a destroy action' do
+ expect(delete('/gitlab/gitlabhq/registry/repository/1/tags/rc1'))
+ .to route_to('projects/registry/tags#destroy',
+ namespace_id: 'gitlab',
+ project_id: 'gitlabhq',
+ repository_id: '1',
+ id: 'rc1')
+ end
+
+ it 'takes registry tag name constrains into account' do
+ expect(delete('/gitlab/gitlabhq/registry/repository/1/tags/-rc1'))
+ .not_to route_to('projects/registry/tags#destroy',
+ namespace_id: 'gitlab',
+ project_id: 'gitlabhq',
+ repository_id: '1',
+ id: '-rc1')
+ end
+ end
+ end
end
diff --git a/spec/rubocop/cop/active_record_dependent_spec.rb b/spec/rubocop/cop/active_record_dependent_spec.rb
new file mode 100644
index 00000000000..599a032bfc5
--- /dev/null
+++ b/spec/rubocop/cop/active_record_dependent_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../rubocop/cop/active_record_dependent'
+
+describe RuboCop::Cop::ActiveRecordDependent do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'inside the app/models directory' do
+ it 'registers an offense when dependent: is used' do
+ allow(cop).to receive(:in_model?).and_return(true)
+
+ inspect_source(cop, 'belongs_to :foo, dependent: :destroy')
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ end
+ end
+ end
+
+ context 'outside the app/models directory' do
+ it 'does nothing' do
+ allow(cop).to receive(:in_model?).and_return(false)
+
+ inspect_source(cop, 'belongs_to :foo, dependent: :destroy')
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+end
diff --git a/spec/rubocop/cop/activerecord_serialize_spec.rb b/spec/rubocop/cop/active_record_serialize_spec.rb
index 5bd7e5fa926..b94b25cecd0 100644
--- a/spec/rubocop/cop/activerecord_serialize_spec.rb
+++ b/spec/rubocop/cop/active_record_serialize_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
-require_relative '../../../rubocop/cop/activerecord_serialize'
+require_relative '../../../rubocop/cop/active_record_serialize'
-describe RuboCop::Cop::ActiverecordSerialize do
+describe RuboCop::Cop::ActiveRecordSerialize do
include CopHelper
subject(:cop) { described_class.new }
diff --git a/spec/rubocop/cop/in_batches_spec.rb b/spec/rubocop/cop/in_batches_spec.rb
new file mode 100644
index 00000000000..072481984c6
--- /dev/null
+++ b/spec/rubocop/cop/in_batches_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../rubocop/cop/in_batches'
+
+describe RuboCop::Cop::InBatches do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ it 'registers an offense when in_batches is used' do
+ inspect_source(cop, 'foo.in_batches do; end')
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/hash_index_spec.rb b/spec/rubocop/cop/migration/hash_index_spec.rb
new file mode 100644
index 00000000000..9a8576a19e5
--- /dev/null
+++ b/spec/rubocop/cop/migration/hash_index_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/hash_index'
+
+describe RuboCop::Cop::Migration::HashIndex do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when creating a hash index' do
+ inspect_source(cop, 'def change; add_index :table, :column, using: :hash; end')
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ end
+ end
+
+ it 'registers an offense when creating a concurrent hash index' do
+ inspect_source(cop, 'def change; add_concurrent_index :table, :column, using: :hash; end')
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ end
+ end
+
+ it 'registers an offense when creating a hash index using t.index' do
+ inspect_source(cop, 'def change; t.index :table, :column, using: :hash; end')
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, 'def change; index :table, :column, using: :hash; end')
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/project_path_helper_spec.rb b/spec/rubocop/cop/project_path_helper_spec.rb
new file mode 100644
index 00000000000..bc47b45cad7
--- /dev/null
+++ b/spec/rubocop/cop/project_path_helper_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../rubocop/cop/project_path_helper'
+
+describe RuboCop::Cop::ProjectPathHelper do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context "when using namespace_project with the project's namespace" do
+ let(:source) { 'edit_namespace_project_issue_path(@issue.project.namespace, @issue.project, @issue)' }
+ let(:correct_source) { 'edit_project_issue_path(@issue.project, @issue)' }
+
+ it 'registers an offense' do
+ inspect_source(cop, source)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['edit_namespace_project_issue_path'])
+ end
+ end
+
+ it 'autocorrects to the right version' do
+ autocorrected = autocorrect_source(cop, source)
+
+ expect(autocorrected).to eq(correct_source)
+ end
+ end
+
+ context 'when using namespace_project with a different namespace' do
+ it 'registers no offense' do
+ inspect_source(cop, 'edit_namespace_project_issue_path(namespace, project)')
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb
index b92c1c28ba8..1332572fffc 100644
--- a/spec/serializers/build_details_entity_spec.rb
+++ b/spec/serializers/build_details_entity_spec.rb
@@ -9,47 +9,96 @@ describe BuildDetailsEntity do
describe '#as_json' do
let(:project) { create(:project, :repository) }
- let!(:build) { create(:ci_build, :failed, project: project) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:build) { create(:ci_build, :failed, pipeline: pipeline) }
let(:request) { double('request') }
- let(:entity) { described_class.new(build, request: request, current_user: user, project: project) }
+
+ let(:entity) do
+ described_class.new(build, request: request,
+ current_user: user,
+ project: project)
+ end
+
subject { entity.as_json }
before do
allow(request).to receive(:current_user).and_return(user)
end
+ it 'contains the needed key value pairs' do
+ expect(subject).to include(:coverage, :erased_at, :duration)
+ expect(subject).to include(:runner, :pipeline)
+ expect(subject).to include(:raw_path, :new_issue_path)
+ end
+
context 'when the user has access to issues and merge requests' do
- let!(:merge_request) do
- create(:merge_request, source_project: project, source_branch: build.ref)
- end
+ context 'when merge request orginates from the same project' do
+ let(:merge_request) do
+ create(:merge_request, source_project: project, source_branch: build.ref)
+ end
- before do
- allow(build).to receive(:merge_request).and_return(merge_request)
- end
+ before do
+ allow(build).to receive(:merge_request).and_return(merge_request)
+ end
+
+ it 'contains the needed key value pairs' do
+ expect(subject).to include(:merge_request)
+ expect(subject).to include(:new_issue_path)
+ end
- it 'contains the needed key value pairs' do
- expect(subject).to include(:coverage, :erased_at, :duration)
- expect(subject).to include(:runner, :pipeline)
- expect(subject).to include(:raw_path, :merge_request)
- expect(subject).to include(:new_issue_path)
+ it 'exposes correct details of the merge request' do
+ expect(subject[:merge_request][:iid]).to eq merge_request.iid
+ end
+
+ it 'has a correct merge request path' do
+ expect(subject[:merge_request][:path]).to include project.full_path
+ end
end
- it 'exposes details of the merge request' do
- expect(subject[:merge_request]).to include(:iid, :path)
+ context 'when merge request is from a fork' do
+ let(:fork_project) do
+ create(:empty_project, forked_from_project: project)
+ end
+
+ let(:pipeline) { create(:ci_pipeline, project: fork_project) }
+
+ before do
+ allow(build).to receive(:merge_request).and_return(merge_request)
+ end
+
+ let(:merge_request) do
+ create(:merge_request, source_project: fork_project,
+ target_project: project,
+ source_branch: build.ref)
+ end
+
+ it 'contains the needed key value pairs' do
+ expect(subject).to include(:merge_request)
+ expect(subject).to include(:new_issue_path)
+ end
+
+ it 'exposes details of the merge request' do
+ expect(subject[:merge_request][:iid]).to eq merge_request.iid
+ end
+
+ it 'has a merge request path to a target project' do
+ expect(subject[:merge_request][:path])
+ .to include project.full_path
+ end
end
- context 'when the build has been erased' do
- let!(:build) { create(:ci_build, :erasable, project: project) }
+ context 'when the build has not been erased' do
+ let(:build) { create(:ci_build, :erasable, project: project) }
- it 'exposes the user whom erased the build' do
+ it 'exposes a build erase path' do
expect(subject).to include(:erase_path)
end
end
context 'when the build has been erased' do
- let!(:build) { create(:ci_build, erased_at: Time.now, project: project, erased_by: user) }
+ let(:build) { create(:ci_build, :erased, project: project) }
- it 'exposes the user whom erased the build' do
+ it 'exposes the user who erased the build' do
expect(subject).to include(:erased_by)
end
end
diff --git a/spec/serializers/deploy_key_entity_spec.rb b/spec/serializers/deploy_key_entity_spec.rb
index ed89fccc3d0..8149de869f1 100644
--- a/spec/serializers/deploy_key_entity_spec.rb
+++ b/spec/serializers/deploy_key_entity_spec.rb
@@ -2,13 +2,15 @@ require 'spec_helper'
describe DeployKeyEntity do
include RequestAwareEntity
-
+
let(:user) { create(:user) }
let(:project) { create(:empty_project, :internal)}
let(:project_private) { create(:empty_project, :private)}
+ let!(:project_pending_delete) { create(:empty_project, :internal, pending_delete: true) }
let(:deploy_key) { create(:deploy_key) }
let!(:deploy_key_internal) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) }
let!(:deploy_key_private) { create(:deploy_keys_project, project: project_private, deploy_key: deploy_key) }
+ let!(:deploy_key_pending_delete) { create(:deploy_keys_project, project: project_pending_delete, deploy_key: deploy_key) }
let(:entity) { described_class.new(deploy_key, user: user) }
@@ -29,7 +31,7 @@ describe DeployKeyEntity do
{
id: project.id,
name: project.name,
- full_path: namespace_project_path(project.namespace, project),
+ full_path: project_path(project),
full_name: project.full_name
}
]
diff --git a/spec/serializers/job_entity_spec.rb b/spec/serializers/job_entity_spec.rb
index 5ca7bf2fcaf..026360e91a3 100644
--- a/spec/serializers/job_entity_spec.rb
+++ b/spec/serializers/job_entity_spec.rb
@@ -7,7 +7,9 @@ describe JobEntity do
let(:request) { double('request') }
before do
+ stub_not_protect_default_branch
allow(request).to receive(:current_user).and_return(user)
+
project.add_developer(user)
end
@@ -77,7 +79,7 @@ describe JobEntity do
project.add_developer(user)
create(:protected_branch, :developers_can_merge,
- name: 'master', project: project)
+ name: job.ref, project: job.project)
end
it 'contains path to play action' do
@@ -90,6 +92,13 @@ describe JobEntity do
end
context 'when user is not allowed to trigger action' do
+ before do
+ allow(job.project).to receive(:empty_repo?).and_return(false)
+
+ create(:protected_branch, :no_one_can_push,
+ name: job.ref, project: job.project)
+ end
+
it 'does not contain path to play action' do
expect(subject).not_to include(:play_path)
end
diff --git a/spec/serializers/merge_request_entity_spec.rb b/spec/serializers/merge_request_entity_spec.rb
index d38433c2365..b3d58b2636f 100644
--- a/spec/serializers/merge_request_entity_spec.rb
+++ b/spec/serializers/merge_request_entity_spec.rb
@@ -47,7 +47,7 @@ describe MergeRequestEntity do
:cancel_merge_when_pipeline_succeeds_path,
:create_issue_to_resolve_discussions_path,
:source_branch_path, :target_branch_commits_path,
- :commits_count)
+ :target_branch_tree_path, :commits_count)
end
it 'has email_patches_path' do
diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb
index d28dec9592a..b990370a271 100644
--- a/spec/serializers/pipeline_details_entity_spec.rb
+++ b/spec/serializers/pipeline_details_entity_spec.rb
@@ -9,6 +9,8 @@ describe PipelineDetailsEntity do
end
before do
+ stub_not_protect_default_branch
+
allow(request).to receive(:current_user).and_return(user)
end
@@ -52,7 +54,7 @@ describe PipelineDetailsEntity do
context 'user has ability to retry pipeline' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it 'retryable flag is true' do
@@ -97,7 +99,7 @@ describe PipelineDetailsEntity do
context 'when pipeline has commit statuses' do
let(:pipeline) { create(:ci_empty_pipeline) }
-
+
before do
create(:generic_commit_status, pipeline: pipeline)
end
diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb
index 46650f3a80d..5b01cc4fc9e 100644
--- a/spec/serializers/pipeline_entity_spec.rb
+++ b/spec/serializers/pipeline_entity_spec.rb
@@ -5,6 +5,8 @@ describe PipelineEntity do
let(:request) { double('request') }
before do
+ stub_not_protect_default_branch
+
allow(request).to receive(:current_user).and_return(user)
end
@@ -52,7 +54,7 @@ describe PipelineEntity do
context 'user has ability to retry pipeline' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it 'contains retry path' do
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index 44813656aff..262bc4acb69 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -108,14 +108,35 @@ describe PipelineSerializer do
end
end
- it 'verifies number of queries', :request_store do
- recorded = ActiveRecord::QueryRecorder.new { subject }
- expect(recorded.count).to be_within(1).of(57)
- expect(recorded.cached_count).to eq(0)
+ shared_examples 'no N+1 queries' do
+ it 'verifies number of queries', :request_store do
+ recorded = ActiveRecord::QueryRecorder.new { subject }
+ expect(recorded.count).to be_within(1).of(59)
+ expect(recorded.cached_count).to eq(0)
+ end
+ end
+
+ context 'with the same ref' do
+ let(:ref) { 'feature' }
+
+ it_behaves_like 'no N+1 queries'
+ end
+
+ context 'with different refs' do
+ def ref
+ @sequence ||= 0
+ @sequence += 1
+ "feature-#{@sequence}"
+ end
+
+ it_behaves_like 'no N+1 queries'
end
def create_pipeline(status)
- create(:ci_empty_pipeline, project: project, status: status).tap do |pipeline|
+ create(:ci_empty_pipeline,
+ project: project,
+ status: status,
+ ref: ref).tap do |pipeline|
Ci::Build::AVAILABLE_STATUSES.each do |status|
create_build(pipeline, status, status)
end
@@ -125,7 +146,7 @@ describe PipelineSerializer do
def create_build(pipeline, stage, status)
create(:ci_build, :tags, :triggered, :artifacts,
pipeline: pipeline, stage: stage,
- name: stage, status: status)
+ name: stage, status: status, ref: pipeline.ref)
end
end
end
diff --git a/spec/services/access_token_validation_service_spec.rb b/spec/services/access_token_validation_service_spec.rb
index 87f093ee8ce..38a3f522504 100644
--- a/spec/services/access_token_validation_service_spec.rb
+++ b/spec/services/access_token_validation_service_spec.rb
@@ -1,41 +1,72 @@
require 'spec_helper'
-describe AccessTokenValidationService, services: true do
+describe AccessTokenValidationService do
describe ".include_any_scope?" do
+ let(:request) { double("request") }
+
it "returns true if the required scope is present in the token's scopes" do
token = double("token", scopes: [:api, :read_user])
+ scopes = [:api]
- expect(described_class.new(token).include_any_scope?([:api])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns true if more than one of the required scopes is present in the token's scopes" do
token = double("token", scopes: [:api, :read_user, :other_scope])
+ scopes = [:api, :other_scope]
- expect(described_class.new(token).include_any_scope?([:api, :other_scope])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns true if the list of required scopes is an exact match for the token's scopes" do
token = double("token", scopes: [:api, :read_user, :other_scope])
+ scopes = [:api, :read_user, :other_scope]
- expect(described_class.new(token).include_any_scope?([:api, :read_user, :other_scope])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns true if the list of required scopes contains all of the token's scopes, in addition to others" do
token = double("token", scopes: [:api, :read_user])
+ scopes = [:api, :read_user, :other_scope]
- expect(described_class.new(token).include_any_scope?([:api, :read_user, :other_scope])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it 'returns true if the list of required scopes is blank' do
token = double("token", scopes: [])
+ scopes = []
- expect(described_class.new(token).include_any_scope?([])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns false if there are no scopes in common between the required scopes and the token scopes" do
token = double("token", scopes: [:api, :read_user])
+ scopes = [:other_scope]
+
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(false)
+ end
+
+ context "conditions" do
+ it "ignores any scopes whose `if` condition returns false" do
+ token = double("token", scopes: [:api, :read_user])
+ scopes = [API::Scope.new(:api, if: ->(_) { false })]
+
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(false)
+ end
+
+ it "does not ignore scopes whose `if` condition is not set" do
+ token = double("token", scopes: [:api, :read_user])
+ scopes = [API::Scope.new(:api, if: ->(_) { false }), :read_user]
+
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
+ end
+
+ it "does not ignore scopes whose `if` condition returns true" do
+ token = double("token", scopes: [:api, :read_user])
+ scopes = [API::Scope.new(:api, if: ->(_) { true }), API::Scope.new(:read_user, if: ->(_) { false })]
- expect(described_class.new(token).include_any_scope?([:other_scope])).to be(false)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
+ end
end
end
end
diff --git a/spec/services/after_branch_delete_service_spec.rb b/spec/services/after_branch_delete_service_spec.rb
index 77ca17bc82c..bc9747d1413 100644
--- a/spec/services/after_branch_delete_service_spec.rb
+++ b/spec/services/after_branch_delete_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe AfterBranchDeleteService, services: true do
+describe AfterBranchDeleteService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, user) }
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 60cb7a9440f..66a8a93b168 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Auth::ContainerRegistryAuthenticationService, services: true do
+describe Auth::ContainerRegistryAuthenticationService do
let(:current_project) { nil }
let(:current_user) { nil }
let(:current_params) { {} }
diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb
index effa4633d13..6e3227303fe 100644
--- a/spec/services/boards/create_service_spec.rb
+++ b/spec/services/boards/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::CreateService, services: true do
+describe Boards::CreateService do
describe '#execute' do
let(:project) { create(:empty_project) }
@@ -26,6 +26,8 @@ describe Boards::CreateService, services: true do
end
it 'does not create a new board' do
+ expect(service).to receive(:can_create_board?) { false }
+
expect { service.execute }.not_to change(project.boards, :count)
end
end
diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb
index 360ee398f77..23ad66e454b 100644
--- a/spec/services/boards/issues/create_service_spec.rb
+++ b/spec/services/boards/issues/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Issues::CreateService, services: true do
+describe Boards::Issues::CreateService do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:board) { create(:board, project: project) }
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index a1e220c2322..b1b5d807a78 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Issues::ListService, services: true do
+describe Boards::Issues::ListService do
describe '#execute' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
@@ -20,7 +20,7 @@ describe Boards::Issues::ListService, services: true do
let!(:opened_issue1) { create(:labeled_issue, project: project, labels: [bug]) }
let!(:opened_issue2) { create(:labeled_issue, project: project, labels: [p2]) }
- let!(:reopened_issue1) { create(:issue, :reopened, project: project) }
+ let!(:reopened_issue1) { create(:issue, :opened, project: project) }
let!(:list1_issue1) { create(:labeled_issue, project: project, labels: [p2, development]) }
let!(:list1_issue2) { create(:labeled_issue, project: project, labels: [development]) }
@@ -67,7 +67,7 @@ describe Boards::Issues::ListService, services: true do
issues = described_class.new(project, user, params).execute
- expect(issues).to eq [closed_issue4, closed_issue2, closed_issue3, closed_issue1]
+ expect(issues).to eq [closed_issue4, closed_issue2, closed_issue5, closed_issue3, closed_issue1]
end
it 'returns opened issues that have label list applied when listing issues from a label list' do
diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb
index 4ff7ac6bb2f..15a32350ae2 100644
--- a/spec/services/boards/issues/move_service_spec.rb
+++ b/spec/services/boards/issues/move_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Issues::MoveService, services: true do
+describe Boards::Issues::MoveService do
describe '#execute' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
@@ -73,7 +73,7 @@ describe Boards::Issues::MoveService, services: true do
issue.reload
expect(issue.labels).to contain_exactly(bug, testing)
- expect(issue).to be_reopened
+ expect(issue).to be_opened
end
end
diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb
index dff33e4bcbb..a95b12eeaa3 100644
--- a/spec/services/boards/list_service_spec.rb
+++ b/spec/services/boards/list_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::ListService, services: true do
+describe Boards::ListService do
describe '#execute' do
let(:project) { create(:empty_project) }
diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb
index ebac38e68f1..86d3227a78d 100644
--- a/spec/services/boards/lists/create_service_spec.rb
+++ b/spec/services/boards/lists/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Lists::CreateService, services: true do
+describe Boards::Lists::CreateService do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:board) { create(:board, project: project) }
diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb
index af2d7c784bb..ad6ae83286d 100644
--- a/spec/services/boards/lists/destroy_service_spec.rb
+++ b/spec/services/boards/lists/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Lists::DestroyService, services: true do
+describe Boards::Lists::DestroyService do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:board) { create(:board, project: project) }
diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb
index ed0337662af..7dec9f7a4a5 100644
--- a/spec/services/boards/lists/generate_service_spec.rb
+++ b/spec/services/boards/lists/generate_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Lists::GenerateService, services: true do
+describe Boards::Lists::GenerateService do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:board) { create(:board, project: project) }
diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb
index 68140759600..c93788d4516 100644
--- a/spec/services/boards/lists/list_service_spec.rb
+++ b/spec/services/boards/lists/list_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Lists::ListService, services: true do
+describe Boards::Lists::ListService do
let(:project) { create(:empty_project) }
let(:board) { create(:board, project: project) }
let(:label) { create(:label, project: project) }
diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb
index 4b3bdd133f2..43e125a21df 100644
--- a/spec/services/boards/lists/move_service_spec.rb
+++ b/spec/services/boards/lists/move_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Boards::Lists::MoveService, services: true do
+describe Boards::Lists::MoveService do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:board) { create(:board, project: project) }
diff --git a/spec/services/chat_names/authorize_user_service_spec.rb b/spec/services/chat_names/authorize_user_service_spec.rb
index d50bfb0492c..d88b2504133 100644
--- a/spec/services/chat_names/authorize_user_service_spec.rb
+++ b/spec/services/chat_names/authorize_user_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatNames::AuthorizeUserService, services: true do
+describe ChatNames::AuthorizeUserService do
describe '#execute' do
let(:service) { create(:service) }
diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb
index 0dc96521fa8..79aaac3aeb6 100644
--- a/spec/services/chat_names/find_user_service_spec.rb
+++ b/spec/services/chat_names/find_user_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatNames::FindUserService, services: true do
+describe ChatNames::FindUserService do
describe '#execute' do
let(:service) { create(:service) }
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 77c07b71c68..4ec495f612e 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1,21 +1,28 @@
require 'spec_helper'
-describe Ci::CreatePipelineService, :services do
+describe Ci::CreatePipelineService do
let(:project) { create(:project, :repository) }
let(:user) { create(:admin) }
+ let(:ref_name) { 'refs/heads/master' }
before do
stub_ci_pipeline_to_return_yaml_file
end
describe '#execute' do
- def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: 'refs/heads/master')
+ def execute_service(
+ source: :push,
+ after: project.commit.id,
+ message: 'Message',
+ ref: ref_name,
+ trigger_request: nil)
params = { ref: ref,
before: '00000000',
after: after,
commits: [{ message: message }] }
- described_class.new(project, user, params).execute(source)
+ described_class.new(project, user, params).execute(
+ source, trigger_request: trigger_request)
end
context 'valid params' do
@@ -40,7 +47,7 @@ describe Ci::CreatePipelineService, :services do
it 'increments the prometheus counter' do
expect(Gitlab::Metrics).to receive(:counter)
- .with(:pipelines_created_count, "Pipelines created count")
+ .with(:pipelines_created_total, "Counter of pipelines created")
.and_call_original
pipeline
@@ -320,5 +327,223 @@ describe Ci::CreatePipelineService, :services do
end.not_to change { Environment.count }
end
end
+
+ context 'when builds with auto-retries are configured' do
+ before do
+ config = YAML.dump(rspec: { script: 'rspec', retry: 2 })
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'correctly creates builds with auto-retry value configured' do
+ pipeline = execute_service
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.find_by(name: 'rspec').retries_max).to eq 2
+ end
+ end
+
+ shared_examples 'when ref is protected' do
+ let(:user) { create(:user) }
+
+ context 'when user is developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'does not create a pipeline' do
+ expect(execute_service).not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'when user is master' do
+ before do
+ project.add_master(user)
+ end
+
+ it 'creates a pipeline' do
+ expect(execute_service).to be_persisted
+ expect(Ci::Pipeline.count).to eq(1)
+ end
+ end
+
+ context 'when trigger belongs to no one' do
+ let(:user) {}
+ let(:trigger_request) { create(:ci_trigger_request) }
+
+ it 'does not create a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'when trigger belongs to a developer' do
+ let(:user) {}
+
+ let(:trigger_request) do
+ create(:ci_trigger_request).tap do |request|
+ user = create(:user)
+ project.add_developer(user)
+ request.trigger.update(owner: user)
+ end
+ end
+
+ it 'does not create a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'when trigger belongs to a master' do
+ let(:user) {}
+
+ let(:trigger_request) do
+ create(:ci_trigger_request).tap do |request|
+ user = create(:user)
+ project.add_master(user)
+ request.trigger.update(owner: user)
+ end
+ end
+
+ it 'does not create a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .to be_persisted
+ expect(Ci::Pipeline.count).to eq(1)
+ end
+ end
+ end
+
+ context 'when ref is a protected branch' do
+ before do
+ create(:protected_branch, project: project, name: 'master')
+ end
+
+ it_behaves_like 'when ref is protected'
+ end
+
+ context 'when ref is a protected tag' do
+ let(:ref_name) { 'refs/tags/v1.0.0' }
+
+ before do
+ create(:protected_tag, project: project, name: '*')
+ end
+
+ it_behaves_like 'when ref is protected'
+ end
+
+ context 'when ref is not protected' do
+ context 'when trigger belongs to no one' do
+ let(:user) {}
+ let(:trigger_request) { create(:ci_trigger_request) }
+
+ it 'creates a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .to be_persisted
+ expect(Ci::Pipeline.count).to eq(1)
+ end
+ end
+ end
+ end
+
+ describe '#allowed_to_create?' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:ref) { 'master' }
+
+ subject do
+ described_class.new(project, user, ref: ref)
+ .send(:allowed_to_create?, user)
+ end
+
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when the branch is protected' do
+ let!(:protected_branch) do
+ create(:protected_branch, project: project, name: ref)
+ end
+
+ it { is_expected.to be_falsey }
+
+ context 'when developers are allowed to merge' do
+ let!(:protected_branch) do
+ create(:protected_branch,
+ :developers_can_merge,
+ project: project,
+ name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'when the tag is protected' do
+ let(:ref) { 'v1.0.0' }
+
+ let!(:protected_tag) do
+ create(:protected_tag, project: project, name: ref)
+ end
+
+ it { is_expected.to be_falsey }
+
+ context 'when developers are allowed to create the tag' do
+ let!(:protected_tag) do
+ create(:protected_tag,
+ :developers_can_create,
+ project: project,
+ name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+
+ context 'when user is a master' do
+ before do
+ project.add_master(user)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when the branch is protected' do
+ let!(:protected_branch) do
+ create(:protected_branch, project: project, name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the tag is protected' do
+ let(:ref) { 'v1.0.0' }
+
+ let!(:protected_tag) do
+ create(:protected_tag, project: project, name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when no one can create the tag' do
+ let!(:protected_tag) do
+ create(:protected_tag,
+ :no_one_can_create,
+ project: project,
+ name: ref)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
+ context 'when owner cannot create pipeline' do
+ it { is_expected.to be_falsey }
+ end
end
end
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index f2956262f4b..8295813a1ca 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -1,12 +1,15 @@
require 'spec_helper'
-describe Ci::CreateTriggerRequestService, services: true do
- let(:service) { described_class.new }
+describe Ci::CreateTriggerRequestService do
+ let(:service) { described_class }
let(:project) { create(:project, :repository) }
- let(:trigger) { create(:ci_trigger, project: project) }
+ let(:trigger) { create(:ci_trigger, project: project, owner: owner) }
+ let(:owner) { create(:user) }
before do
stub_ci_pipeline_to_return_yaml_file
+
+ project.add_developer(owner)
end
describe '#execute' do
@@ -14,29 +17,26 @@ describe Ci::CreateTriggerRequestService, services: true do
subject { service.execute(project, trigger, 'master') }
context 'without owner' do
- it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request.builds.first).to be_kind_of(Ci::Build) }
it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) }
it { expect(subject.pipeline).to be_trigger }
- it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
end
context 'with owner' do
- let(:owner) { create(:user) }
- let(:trigger) { create(:ci_trigger, project: project, owner: owner) }
-
- it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request.builds.first).to be_kind_of(Ci::Build) }
+ it { expect(subject.trigger_request.builds.first.user).to eq(owner) }
it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) }
it { expect(subject.pipeline).to be_trigger }
it { expect(subject.pipeline.user).to eq(owner) }
- it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
- it { expect(subject.builds.first.user).to eq(owner) }
end
end
context 'no commit for ref' do
subject { service.execute(project, trigger, 'other-branch') }
- it { expect(subject).to be_nil }
+ it { expect(subject.pipeline).not_to be_persisted }
end
context 'no builds created' do
@@ -46,7 +46,7 @@ describe Ci::CreateTriggerRequestService, services: true do
stub_ci_pipeline_yaml_file('script: { only: [develop], script: hello World }')
end
- it { expect(subject).to be_nil }
+ it { expect(subject.pipeline).not_to be_persisted }
end
end
end
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
new file mode 100644
index 00000000000..945a2fe1a6b
--- /dev/null
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -0,0 +1,83 @@
+require 'spec_helper'
+
+describe Ci::PipelineTriggerService, services: true do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
+
+ describe '#execute' do
+ let(:user) { create(:user) }
+ let(:trigger) { create(:ci_trigger, project: project, owner: user) }
+ let(:result) { described_class.new(project, user, params).execute }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when trigger belongs to a different project' do
+ let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
+ let(:trigger) { create(:ci_trigger, project: create(:empty_project), owner: user) }
+
+ it 'does nothing' do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ end
+ end
+
+ context 'when params have an existsed trigger token' do
+ context 'when params have an existsed ref' do
+ let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
+
+ it 'triggers a pipeline' do
+ expect { result }.to change { Ci::Pipeline.count }.by(1)
+ expect(result[:pipeline].ref).to eq('master')
+ expect(result[:pipeline].project).to eq(project)
+ expect(result[:pipeline].user).to eq(trigger.owner)
+ expect(result[:status]).to eq(:success)
+ end
+
+ context 'when commit message has [ci skip]' do
+ before do
+ allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' }
+ end
+
+ it 'ignores [ci skip] and create as general' do
+ expect { result }.to change { Ci::Pipeline.count }.by(1)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'when params have a variable' do
+ let(:params) { { token: trigger.token, ref: 'master', variables: variables } }
+ let(:variables) { { 'AAA' => 'AAA123' } }
+
+ it 'has a variable' do
+ expect { result }.to change { Ci::PipelineVariable.count }.by(1)
+ .and change { Ci::TriggerRequest.count }.by(1)
+ expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
+ expect(result[:pipeline].trigger_requests.last.variables).to be_nil
+ end
+ end
+ end
+
+ context 'when params have a non-existsed ref' do
+ let(:params) { { token: trigger.token, ref: 'invalid-ref', variables: nil } }
+
+ it 'does not trigger a pipeline' do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ expect(result[:http_status]).to eq(400)
+ end
+ end
+ end
+
+ context 'when params have a non-existsed trigger token' do
+ let(:params) { { token: 'invalid-token', ref: nil, variables: nil } }
+
+ it 'does not trigger a pipeline' do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ expect(result).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index ea211de1f82..1ced26ff98d 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::PlayBuildService, '#execute', :services do
+describe Ci::PlayBuildService, '#execute' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
index 1557cb3c938..3a702742681 100644
--- a/spec/services/ci/process_pipeline_service_spec.rb
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::ProcessPipelineService, '#execute', :services do
+describe Ci::ProcessPipelineService, '#execute' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
@@ -9,6 +9,8 @@ describe Ci::ProcessPipelineService, '#execute', :services do
end
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
@@ -62,6 +64,10 @@ describe Ci::ProcessPipelineService, '#execute', :services do
fail_running_or_pending
expect(builds_statuses).to eq %w(failed pending)
+
+ fail_running_or_pending
+
+ expect(pipeline.reload).to be_success
end
end
@@ -459,6 +465,35 @@ describe Ci::ProcessPipelineService, '#execute', :services do
end
end
+ context 'when builds with auto-retries are configured' do
+ before do
+ create_build('build:1', stage_idx: 0, user: user, options: { retry: 2 })
+ create_build('test:1', stage_idx: 1, user: user, when: :on_failure)
+ create_build('test:2', stage_idx: 1, user: user, options: { retry: 1 })
+ end
+
+ it 'automatically retries builds in a valid order' do
+ expect(process_pipeline).to be_truthy
+
+ fail_running_or_pending
+
+ expect(builds_names).to eq %w[build:1 build:1]
+ expect(builds_statuses).to eq %w[failed pending]
+
+ succeed_running_or_pending
+
+ expect(builds_names).to eq %w[build:1 build:1 test:2]
+ expect(builds_statuses).to eq %w[failed success pending]
+
+ succeed_running_or_pending
+
+ expect(builds_names).to eq %w[build:1 build:1 test:2]
+ expect(builds_statuses).to eq %w[failed success success]
+
+ expect(pipeline.reload).to be_success
+ end
+ end
+
def process_pipeline
described_class.new(pipeline.project, user).execute(pipeline)
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 62ba0b01339..23c0f715c3e 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
module Ci
- describe RegisterJobService, services: true do
+ describe RegisterJobService do
let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline }
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index ef9927c5969..fd8a57d28f0 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::RetryBuildService, :services do
+describe Ci::RetryBuildService do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
@@ -85,6 +85,8 @@ describe Ci::RetryBuildService, :services do
context 'when user has ability to execute build' do
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
@@ -131,6 +133,8 @@ describe Ci::RetryBuildService, :services do
context 'when user has ability to execute build' do
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 3e860203063..90b0c5a4dce 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::RetryPipelineService, '#execute', :services do
+describe Ci::RetryPipelineService, '#execute' do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
@@ -244,13 +244,9 @@ describe Ci::RetryPipelineService, '#execute', :services do
create_build('verify', :canceled, 1)
end
- it 'does not reprocess manual action' do
- service.execute(pipeline)
-
- expect(build('test')).to be_pending
- expect(build('deploy')).to be_failed
- expect(build('verify')).to be_created
- expect(pipeline.reload).to be_running
+ it 'raises an error' do
+ expect { service.execute(pipeline) }
+ .to raise_error Gitlab::Access::AccessDeniedError
end
end
@@ -261,13 +257,9 @@ describe Ci::RetryPipelineService, '#execute', :services do
create_build('verify', :canceled, 2)
end
- it 'does not reprocess manual action' do
- service.execute(pipeline)
-
- expect(build('test')).to be_pending
- expect(build('deploy')).to be_failed
- expect(build('verify')).to be_created
- expect(pipeline.reload).to be_running
+ it 'raises an error' do
+ expect { service.execute(pipeline) }
+ .to raise_error Gitlab::Access::AccessDeniedError
end
end
end
diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb
index 98044ad232e..e2a9ed27e87 100644
--- a/spec/services/ci/stop_environments_service_spec.rb
+++ b/spec/services/ci/stop_environments_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::StopEnvironmentsService, services: true do
+describe Ci::StopEnvironmentsService do
let(:project) { create(:project, :private, :repository) }
let(:user) { create(:user) }
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index efefa8e8eca..0da0e57dbcd 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::UpdateBuildQueueService, :services do
+describe Ci::UpdateBuildQueueService do
let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:pipeline) { create(:ci_pipeline, project: project) }
diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb
index e429fcfc72f..7cc04c92d27 100644
--- a/spec/services/ci/update_runner_service_spec.rb
+++ b/spec/services/ci/update_runner_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::UpdateRunnerService, :services do
+describe Ci::UpdateRunnerService do
let(:runner) { create(:ci_runner) }
describe '#update' do
diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb
index bea7c965233..9e15eae8c13 100644
--- a/spec/services/compare_service_spec.rb
+++ b/spec/services/compare_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CompareService, services: true do
+describe CompareService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, 'feature') }
diff --git a/spec/services/create_branch_service_spec.rb b/spec/services/create_branch_service_spec.rb
index 3f548688c20..38096a080a7 100644
--- a/spec/services/create_branch_service_spec.rb
+++ b/spec/services/create_branch_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateBranchService, services: true do
+describe CreateBranchService do
let(:user) { create(:user) }
let(:service) { described_class.new(project, user) }
diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb
index dfab6ebf372..049b082277a 100644
--- a/spec/services/create_deployment_service_spec.rb
+++ b/spec/services/create_deployment_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateDeploymentService, services: true do
+describe CreateDeploymentService do
let(:user) { create(:user) }
let(:options) { nil }
@@ -244,6 +244,8 @@ describe CreateDeploymentService, services: true do
context 'when job is retried' do
it_behaves_like 'creates deployment' do
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb
index 271ccfe7968..ac0a0458f56 100644
--- a/spec/services/create_release_service_spec.rb
+++ b/spec/services/create_release_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe CreateReleaseService, services: true do
+describe CreateReleaseService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:tag_name) { project.repository.tag_names.first }
let(:description) { 'Awesome release!' }
- let(:service) { CreateReleaseService.new(project, user) }
+ let(:service) { described_class.new(project, user) }
it 'creates a new release' do
result = service.execute(tag_name, description)
diff --git a/spec/services/create_snippet_service_spec.rb b/spec/services/create_snippet_service_spec.rb
index d81d0fd76c9..b6ab6b8271c 100644
--- a/spec/services/create_snippet_service_spec.rb
+++ b/spec/services/create_snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateSnippetService, services: true do
+describe CreateSnippetService do
before do
@user = create :user
@admin = create :user, admin: true
diff --git a/spec/services/delete_branch_service_spec.rb b/spec/services/delete_branch_service_spec.rb
index c4685c9aa31..19855c9bee2 100644
--- a/spec/services/delete_branch_service_spec.rb
+++ b/spec/services/delete_branch_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DeleteBranchService, services: true do
+describe DeleteBranchService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb
index cae74df9c90..4b872d667cf 100644
--- a/spec/services/delete_merged_branches_service_spec.rb
+++ b/spec/services/delete_merged_branches_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DeleteMergedBranchesService, services: true do
+describe DeleteMergedBranchesService do
subject(:service) { described_class.new(project, project.owner) }
let(:project) { create(:project, :repository) }
@@ -24,6 +24,14 @@ describe DeleteMergedBranchesService, services: true do
expect(project.repository.branch_names).to include('master')
end
+ it 'keeps protected branches' do
+ create(:protected_branch, project: project, name: 'improve/awesome')
+
+ service.execute
+
+ expect(project.repository.branch_names).to include('improve/awesome')
+ end
+
context 'user without rights' do
let(:user) { create(:user) }
@@ -35,7 +43,7 @@ describe DeleteMergedBranchesService, services: true do
context 'open merge requests' do
it 'does not delete branches from open merge requests' do
fork_link = create(:forked_project_link, forked_from_project: project)
- create(:merge_request, :reopened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master')
+ create(:merge_request, :opened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master')
create(:merge_request, :opened, source_project: fork_link.forked_to_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master')
service.execute
diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb
index 177e32e13bd..c239494298b 100644
--- a/spec/services/discussions/update_diff_position_service_spec.rb
+++ b/spec/services/discussions/update_diff_position_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Discussions::UpdateDiffPositionService, services: true do
+describe Discussions::UpdateDiffPositionService do
let(:project) { create(:project, :repository) }
let(:current_user) { project.owner }
let(:create_commit) { project.commit("913c66a37b4a45b9769037c55c2d238bd0942d2e") }
diff --git a/spec/services/emails/create_service_spec.rb b/spec/services/emails/create_service_spec.rb
new file mode 100644
index 00000000000..641d5538de8
--- /dev/null
+++ b/spec/services/emails/create_service_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Emails::CreateService do
+ let(:user) { create(:user) }
+ let(:opts) { { email: 'new@email.com' } }
+
+ subject(:service) { described_class.new(user, opts) }
+
+ describe '#execute' do
+ it 'creates an email with valid attributes' do
+ expect { service.execute }.to change { Email.count }.by(1)
+ expect(Email.where(opts)).not_to be_empty
+ end
+
+ it 'has the right user association' do
+ service.execute
+
+ expect(user.emails).to eq(Email.where(opts))
+ end
+ end
+end
diff --git a/spec/services/emails/destroy_service_spec.rb b/spec/services/emails/destroy_service_spec.rb
new file mode 100644
index 00000000000..1f4294dd905
--- /dev/null
+++ b/spec/services/emails/destroy_service_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe Emails::DestroyService do
+ let!(:user) { create(:user) }
+ let!(:email) { create(:email, user: user) }
+
+ subject(:service) { described_class.new(user, email: email.email) }
+
+ describe '#execute' do
+ it 'removes an email' do
+ expect { service.execute }.to change { user.emails.count }.by(-1)
+ end
+ end
+end
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index b06cefe071d..00104ae1fd9 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe EventCreateService, services: true do
+describe EventCreateService do
include UserActivitiesHelpers
- let(:service) { EventCreateService.new }
+ let(:service) { described_class.new }
describe 'Issues' do
describe '#open_issue' do
@@ -113,7 +113,7 @@ describe EventCreateService, services: true do
end
end
- describe '#push', :redis do
+ describe '#push', :clean_gitlab_redis_shared_state do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb
index ac7ccfbaab0..3ce01a995b4 100644
--- a/spec/services/git_hooks_service_spec.rb
+++ b/spec/services/git_hooks_service_spec.rb
@@ -1,18 +1,17 @@
require 'spec_helper'
-describe GitHooksService, services: true do
+describe GitHooksService do
include RepoHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
- let(:service) { GitHooksService.new }
+ let(:service) { described_class.new }
before do
@blankrev = Gitlab::Git::BLANK_SHA
@oldrev = sample_commit.parent_id
@newrev = sample_commit.id
@ref = 'refs/heads/feature'
- @repo_path = project.repository.path_to_repo
end
describe '#execute' do
@@ -21,7 +20,7 @@ describe GitHooksService, services: true do
hook = double(trigger: [true, nil])
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
- service.execute(user, @repo_path, @blankrev, @newrev, @ref) { }
+ service.execute(user, project, @blankrev, @newrev, @ref) { }
end
end
@@ -31,7 +30,7 @@ describe GitHooksService, services: true do
expect(service).not_to receive(:run_hook).with('post-receive')
expect do
- service.execute(user, @repo_path, @blankrev, @newrev, @ref)
+ service.execute(user, project, @blankrev, @newrev, @ref)
end.to raise_error(GitHooksService::PreReceiveError)
end
end
@@ -43,7 +42,7 @@ describe GitHooksService, services: true do
expect(service).not_to receive(:run_hook).with('post-receive')
expect do
- service.execute(user, @repo_path, @blankrev, @newrev, @ref)
+ service.execute(user, project, @blankrev, @newrev, @ref)
end.to raise_error(GitHooksService::PreReceiveError)
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index ca827fc0f39..3fb677b65be 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -3,27 +3,24 @@ require 'spec_helper'
describe GitPushService, services: true do
include RepoHelpers
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:blankrev) { Gitlab::Git::BLANK_SHA }
+ let(:oldrev) { sample_commit.parent_id }
+ let(:newrev) { sample_commit.id }
+ let(:ref) { 'refs/heads/master' }
before do
project.team << [user, :master]
- @blankrev = Gitlab::Git::BLANK_SHA
- @oldrev = sample_commit.parent_id
- @newrev = sample_commit.id
- @ref = 'refs/heads/master'
end
describe 'Push branches' do
- let(:oldrev) { @oldrev }
- let(:newrev) { @newrev }
-
subject do
- execute_service(project, user, oldrev, newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
context 'new branch' do
- let(:oldrev) { @blankrev }
+ let(:oldrev) { blankrev }
it { is_expected.to be_truthy }
@@ -51,7 +48,7 @@ describe GitPushService, services: true do
end
context 'rm branch' do
- let(:newrev) { @blankrev }
+ let(:newrev) { blankrev }
it { is_expected.to be_truthy }
@@ -70,24 +67,20 @@ describe GitPushService, services: true do
end
describe "Git Push Data" do
- before do
- service = execute_service(project, user, @oldrev, @newrev, @ref )
- @push_data = service.push_data
- @commit = project.commit(@newrev)
- end
+ let(:commit) { project.commit(newrev) }
- subject { @push_data }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref) }
it { is_expected.to include(object_kind: 'push') }
- it { is_expected.to include(before: @oldrev) }
- it { is_expected.to include(after: @newrev) }
- it { is_expected.to include(ref: @ref) }
+ it { is_expected.to include(before: oldrev) }
+ it { is_expected.to include(after: newrev) }
+ it { is_expected.to include(ref: ref) }
it { is_expected.to include(user_id: user.id) }
it { is_expected.to include(user_name: user.name) }
it { is_expected.to include(project_id: project.id) }
context "with repository data" do
- subject { @push_data[:repository] }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:repository] }
it { is_expected.to include(name: project.name) }
it { is_expected.to include(url: project.url_to_repo) }
@@ -96,7 +89,7 @@ describe GitPushService, services: true do
end
context "with commits" do
- subject { @push_data[:commits] }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits] }
it { is_expected.to be_an(Array) }
it 'has 1 element' do
@@ -104,11 +97,11 @@ describe GitPushService, services: true do
end
context "the commit" do
- subject { @push_data[:commits].first }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits].first }
- it { is_expected.to include(id: @commit.id) }
- it { is_expected.to include(message: @commit.safe_message) }
- it { is_expected.to include(timestamp: @commit.date.xmlschema) }
+ it { is_expected.to include(id: commit.id) }
+ it { is_expected.to include(message: commit.safe_message) }
+ it { expect(subject[:timestamp].in_time_zone).to eq(commit.date.in_time_zone) }
it do
is_expected.to include(
url: [
@@ -116,23 +109,23 @@ describe GitPushService, services: true do
project.namespace.to_param,
project.to_param,
'commit',
- @commit.id
+ commit.id
].join('/')
)
end
context "with a author" do
- subject { @push_data[:commits].first[:author] }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits].first[:author] }
- it { is_expected.to include(name: @commit.author_name) }
- it { is_expected.to include(email: @commit.author_email) }
+ it { is_expected.to include(name: commit.author_name) }
+ it { is_expected.to include(email: commit.author_email) }
end
end
end
end
describe "Pipelines" do
- subject { execute_service(project, user, @oldrev, @newrev, @ref) }
+ subject { execute_service(project, user, oldrev, newrev, ref) }
before do
stub_ci_pipeline_to_return_yaml_file
@@ -145,29 +138,26 @@ describe GitPushService, services: true do
end
describe "Push Event" do
- before do
- service = execute_service(project, user, @oldrev, @newrev, @ref )
- @event = Event.find_by_action(Event::PUSHED)
- @push_data = service.push_data
- end
+ let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) }
+ let(:event) { Event.find_by_action(Event::PUSHED) }
- it { expect(@event).not_to be_nil }
- it { expect(@event.project).to eq(project) }
- it { expect(@event.action).to eq(Event::PUSHED) }
- it { expect(@event.data).to eq(@push_data) }
+ it { expect(event).not_to be_nil }
+ it { expect(event.project).to eq(project) }
+ it { expect(event.action).to eq(Event::PUSHED) }
+ it { expect(event.data).to eq(push_data) }
context "Updates merge requests" do
it "when pushing a new branch for the first time" do
expect(UpdateMergeRequestsWorker).to receive(:perform_async)
- .with(project.id, user.id, @blankrev, 'newrev', 'refs/heads/master')
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ .with(project.id, user.id, blankrev, 'newrev', ref)
+ execute_service(project, user, blankrev, 'newrev', ref )
end
end
-
+
context "Sends System Push data" do
it "when pushing on a branch" do
- expect(SystemHookPushWorker).to receive(:perform_async).with(@push_data, :push_hooks)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ expect(SystemHookPushWorker).to receive(:perform_async).with(push_data, :push_hooks)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
end
@@ -177,13 +167,13 @@ describe GitPushService, services: true do
it "calls the copy attributes method for the first push to the default branch" do
expect(project.repository).to receive(:copy_gitattributes).with('master')
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master')
+ execute_service(project, user, blankrev, 'newrev', ref)
end
it "calls the copy attributes method for changes to the default branch" do
- expect(project.repository).to receive(:copy_gitattributes).with('refs/heads/master')
+ expect(project.repository).to receive(:copy_gitattributes).with(ref)
- execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master')
+ execute_service(project, user, 'oldrev', 'newrev', ref)
end
end
@@ -196,7 +186,7 @@ describe GitPushService, services: true do
it "does not call copy attributes method" do
expect(project.repository).not_to receive(:copy_gitattributes)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
end
@@ -206,7 +196,7 @@ describe GitPushService, services: true do
it "when pushing a branch for the first time" do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER])
expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER])
@@ -217,7 +207,7 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).to be_empty
end
@@ -227,7 +217,7 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER])
@@ -242,7 +232,7 @@ describe GitPushService, services: true do
expect(project.default_branch).to eq("master")
expect_any_instance_of(ProtectedBranches::CreateService).not_to receive(:execute)
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::NO_ACCESS])
@@ -254,7 +244,7 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER])
expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER])
@@ -262,7 +252,7 @@ describe GitPushService, services: true do
it "when pushing new commits to existing branch" do
expect(project).to receive(:execute_hooks)
- execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master' )
+ execute_service(project, user, 'oldrev', 'newrev', ref)
end
end
end
@@ -292,7 +282,7 @@ describe GitPushService, services: true do
it "creates a note if a pushed commit mentions an issue" do
expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "only creates a cross-reference note if one doesn't already exist" do
@@ -300,7 +290,7 @@ describe GitPushService, services: true do
expect(SystemNoteService).not_to receive(:cross_reference).with(issue, commit, commit_author)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "defaults to the pushing user if the commit's author is not known" do
@@ -310,16 +300,16 @@ describe GitPushService, services: true do
)
expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, user)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "finds references in the first push to a non-default branch" do
- allow(project.repository).to receive(:commits_between).with(@blankrev, @newrev).and_return([])
- allow(project.repository).to receive(:commits_between).with("master", @newrev).and_return([commit])
+ allow(project.repository).to receive(:commits_between).with(blankrev, newrev).and_return([])
+ allow(project.repository).to receive(:commits_between).with("master", newrev).and_return([commit])
expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author)
- execute_service(project, user, @blankrev, @newrev, 'refs/heads/other' )
+ execute_service(project, user, blankrev, newrev, 'refs/heads/other')
end
end
@@ -349,14 +339,14 @@ describe GitPushService, services: true do
context "while saving the 'first_mentioned_in_commit_at' metric for an issue" do
it 'sets the metric for referenced issues' do
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
expect(issue.reload.metrics.first_mentioned_in_commit_at).to be_like_time(commit_time)
end
it 'does not set the metric for non-referenced issues' do
non_referenced_issue = create(:issue, project: project)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
expect(non_referenced_issue.reload.metrics.first_mentioned_in_commit_at).to be_nil
end
@@ -388,30 +378,18 @@ describe GitPushService, services: true do
context "to default branches" do
it "closes issues" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
expect(Issue.find(issue.id)).to be_closed
end
it "adds a note indicating that the issue is now closed" do
expect(SystemNoteService).to receive(:change_status).with(issue, project, commit_author, "closed", closing_commit)
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
end
it "doesn't create additional cross-reference notes" do
expect(SystemNoteService).not_to receive(:cross_reference)
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
- end
-
- it "doesn't close issues when external issue tracker is in use" do
- allow_any_instance_of(Project).to receive(:default_issues_tracker?)
- .and_return(false)
- external_issue_tracker = double(title: 'My Tracker', issue_path: issue.iid, reference_pattern: project.issue_reference_pattern)
- allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(external_issue_tracker)
-
- # The push still shouldn't create cross-reference notes.
- expect do
- execute_service(project, commit_author, @oldrev, @newrev, 'refs/heads/hurf' )
- end.not_to change { Note.where(project_id: project.id, system: true).count }
+ execute_service(project, commit_author, oldrev, newrev, ref)
end
end
@@ -423,11 +401,11 @@ describe GitPushService, services: true do
it "creates cross-reference notes" do
expect(SystemNoteService).to receive(:cross_reference).with(issue, closing_commit, commit_author)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "doesn't close issues" do
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
expect(Issue.find(issue.id)).to be_opened
end
end
@@ -444,11 +422,12 @@ describe GitPushService, services: true do
stub_jira_urls("JIRA-1")
allow(closing_commit).to receive_messages({
- issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern),
- safe_message: message,
- author_name: commit_author.name,
- author_email: commit_author.email
- })
+ issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern),
+ safe_message: message,
+ author_name: commit_author.name,
+ author_email: commit_author.email
+ })
+
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
allow(project.repository).to receive_messages(commits_between: [closing_commit])
@@ -462,7 +441,7 @@ describe GitPushService, services: true do
let(:message) { "this is some work.\n\nrelated to JIRA-1" }
it "initiates one api call to jira server to mention the issue" do
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
body: /mentioned this issue in/
@@ -472,7 +451,11 @@ describe GitPushService, services: true do
context "closing an issue" do
let(:message) { "this is some work.\n\ncloses JIRA-1" }
- let(:comment_body) { { body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]." }.to_json }
+ let(:comment_body) do
+ {
+ body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]."
+ }.to_json
+ end
before do
open_issue = JIRA::Resource::Issue.new(jira_tracker.client, attrs: { "id" => "JIRA-1" })
@@ -486,13 +469,13 @@ describe GitPushService, services: true do
context "using right markdown" do
it "initiates one api call to jira server to close the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once
end
it "initiates one api call to jira server to comment on the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
body: comment_body
@@ -500,21 +483,57 @@ describe GitPushService, services: true do
end
end
- context "using wrong markdown" do
- let(:message) { "this is some work.\n\ncloses #1" }
+ context "using internal issue reference" do
+ context 'when internal issues are disabled' do
+ before do
+ project.issues_enabled = false
+ project.save!
+ end
+ let(:message) { "this is some work.\n\ncloses #1" }
+
+ it "does not initiates one api call to jira server to close the issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
- it "does not initiates one api call to jira server to close the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1'))
+ end
- expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1'))
+ it "does not initiates one api call to jira server to comment on the issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+
+ expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
+ body: comment_body
+ ).once
+ end
end
- it "does not initiates one api call to jira server to comment on the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ context 'when internal issues are enabled' do
+ let(:issue) { create(:issue, project: project) }
+ let(:message) { "this is some work.\n\ncloses JIRA-1 \n\n closes #{issue.to_reference}" }
- expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
- body: comment_body
- ).once
+ it "initiates one api call to jira server to close the jira issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+
+ expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once
+ end
+
+ it "initiates one api call to jira server to comment on the jira issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+
+ expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
+ body: comment_body
+ ).once
+ end
+
+ it "closes the internal issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+ expect(issue.reload).to be_closed
+ end
+
+ it "adds a note indicating that the issue is now closed" do
+ expect(SystemNoteService).to receive(:change_status)
+ .with(issue, project, commit_author, "closed", closing_commit)
+ execute_service(project, commit_author, oldrev, newrev, ref)
+ end
end
end
end
@@ -523,7 +542,7 @@ describe GitPushService, services: true do
describe "empty project" do
let(:project) { create(:project_empty_repo) }
- let(:new_ref) { 'refs/heads/feature'}
+ let(:new_ref) { 'refs/heads/feature' }
before do
allow(project).to receive(:default_branch).and_return('feature')
@@ -531,7 +550,7 @@ describe GitPushService, services: true do
end
it 'push to first branch updates HEAD' do
- execute_service(project, user, @blankrev, @newrev, new_ref )
+ execute_service(project, user, blankrev, newrev, new_ref)
end
end
@@ -539,20 +558,24 @@ describe GitPushService, services: true do
let(:housekeeping) { Projects::HousekeepingService.new(project) }
before do
- # Flush any raw Redis data stored by the housekeeping code.
- Gitlab::Redis.with { |conn| conn.flushall }
+ # Flush any raw key-value data stored by the housekeeping code.
+ Gitlab::Redis::Cache.with { |conn| conn.flushall }
+ Gitlab::Redis::Queues.with { |conn| conn.flushall }
+ Gitlab::Redis::SharedState.with { |conn| conn.flushall }
allow(Projects::HousekeepingService).to receive(:new).and_return(housekeeping)
end
after do
- Gitlab::Redis.with { |conn| conn.flushall }
+ Gitlab::Redis::Cache.with { |conn| conn.flushall }
+ Gitlab::Redis::Queues.with { |conn| conn.flushall }
+ Gitlab::Redis::SharedState.with { |conn| conn.flushall }
end
it 'does not perform housekeeping when not needed' do
expect(housekeeping).not_to receive(:execute)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
context 'when housekeeping is needed' do
@@ -563,20 +586,20 @@ describe GitPushService, services: true do
it 'performs housekeeping' do
expect(housekeeping).to receive(:execute)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
it 'does not raise an exception' do
allow(housekeeping).to receive(:try_obtain_lease).and_return(false)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
it 'increments the push counter' do
expect(housekeeping).to receive(:increment!)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
@@ -584,9 +607,9 @@ describe GitPushService, services: true do
let(:service) do
described_class.new(project,
user,
- oldrev: sample_commit.parent_id,
- newrev: sample_commit.id,
- ref: 'refs/heads/master')
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref)
end
context 'on the default branch' do
@@ -629,14 +652,13 @@ describe GitPushService, services: true do
let(:service) do
described_class.new(project,
user,
- oldrev: sample_commit.parent_id,
- newrev: sample_commit.id,
- ref: 'refs/heads/master')
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref)
end
it 'only schedules a limited number of commits' do
- allow(service).to receive(:push_commits)
- .and_return(Array.new(1000, double(:commit, to_hash: {}, matches_cross_reference_regex?: true)))
+ service.push_commits = Array.new(1000, double(:commit, to_hash: {}, matches_cross_reference_regex?: true))
expect(ProcessCommitWorker).to receive(:perform_async).exactly(100).times
@@ -644,8 +666,7 @@ describe GitPushService, services: true do
end
it "skips commits which don't include cross-references" do
- allow(service).to receive(:push_commits)
- .and_return([double(:commit, to_hash: {}, matches_cross_reference_regex?: false)])
+ service.push_commits = [double(:commit, to_hash: {}, matches_cross_reference_regex?: false)]
expect(ProcessCommitWorker).not_to receive(:perform_async)
@@ -653,9 +674,31 @@ describe GitPushService, services: true do
end
end
+ describe '#update_signatures' do
+ let(:service) do
+ described_class.new(
+ project,
+ user,
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: 'refs/heads/master'
+ )
+ end
+
+ it 'calls CreateGpgSignatureWorker.perform_async for each commit' do
+ expect(CreateGpgSignatureWorker).to receive(:perform_async).with(sample_commit.id, project.id)
+
+ execute_service(project, user, oldrev, newrev, ref)
+ end
+ end
+
def execute_service(project, user, oldrev, newrev, ref)
- service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref )
+ service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
service.execute
service
end
+
+ def push_data_from_service(project, user, oldrev, newrev, ref)
+ execute_service(project, user, oldrev, newrev, ref).push_data
+ end
end
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index 1fdcb420a8b..f877c145390 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe GitTagPushService, services: true do
+describe GitTagPushService do
include RepoHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
- let(:service) { GitTagPushService.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) }
+ let(:service) { described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) }
let(:oldrev) { Gitlab::Git::BLANK_SHA }
let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0
@@ -184,7 +184,7 @@ describe GitTagPushService, services: true do
describe "Webhooks" do
context "execute webhooks" do
- let(:service) { GitTagPushService.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') }
+ let(:service) { described_class.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') }
it "when pushing tags" do
expect(project).to receive(:execute_hooks)
diff --git a/spec/services/gravatar_service_spec.rb b/spec/services/gravatar_service_spec.rb
index 8c4ad8c7a3e..d2cc53fe0ee 100644
--- a/spec/services/gravatar_service_spec.rb
+++ b/spec/services/gravatar_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GravatarService, service: true do
+describe GravatarService do
describe '#execute' do
let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' }
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index fbd9026640c..b2175717a70 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Groups::CreateService, '#execute', services: true do
+describe Groups::CreateService, '#execute' do
let!(:user) { create(:user) }
let!(:group_params) { { path: "group_path", visibility_level: Gitlab::VisibilityLevel::PUBLIC } }
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index a37257d1bf4..c18870ea100 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Groups::DestroyService, services: true do
+describe Groups::DestroyService do
include DatabaseConnectionHelpers
let!(:user) { create(:user) }
@@ -15,6 +15,14 @@ describe Groups::DestroyService, services: true do
group.add_user(user, Gitlab::Access::OWNER)
end
+ def destroy_group(group, user, async)
+ if async
+ Groups::DestroyService.new(group, user).async_execute
+ else
+ Groups::DestroyService.new(group, user).execute
+ end
+ end
+
shared_examples 'group destruction' do |async|
context 'database records' do
before do
@@ -27,33 +35,27 @@ describe Groups::DestroyService, services: true do
it { expect(NotificationSetting.unscoped.all).not_to include(notification_setting) }
end
+ context 'mattermost team' do
+ let!(:chat_team) { create(:chat_team, namespace: group) }
+
+ it 'destroys the team too' do
+ expect_any_instance_of(Mattermost::Team).to receive(:destroy)
+
+ destroy_group(group, user, async)
+ end
+ end
+
context 'file system' do
context 'Sidekiq inline' do
before do
- # Run sidekiq immediatly to check that renamed dir will be removed
+ # Run sidekiq immediately to check that renamed dir will be removed
Sidekiq::Testing.inline! { destroy_group(group, user, async) }
end
- it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
- it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey }
- end
-
- context 'Sidekiq fake' do
- before do
- # Don't run sidekiq to check if renamed repository exists
- Sidekiq::Testing.fake! { destroy_group(group, user, async) }
+ it 'verifies that paths have been deleted' do
+ expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey
+ expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey
end
-
- it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
- it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_truthy }
- end
- end
-
- def destroy_group(group, user, async)
- if async
- Groups::DestroyService.new(group, user).async_execute
- else
- Groups::DestroyService.new(group, user).execute
end
end
end
@@ -61,6 +63,26 @@ describe Groups::DestroyService, services: true do
describe 'asynchronous delete' do
it_behaves_like 'group destruction', true
+ context 'Sidekiq fake' do
+ before do
+ # Don't run Sidekiq to verify that group and projects are not actually destroyed
+ Sidekiq::Testing.fake! { destroy_group(group, user, true) }
+ end
+
+ after do
+ # Clean up stale directories
+ gitlab_shell.rm_namespace(project.repository_storage_path, group.path)
+ gitlab_shell.rm_namespace(project.repository_storage_path, remove_path)
+ end
+
+ it 'verifies original paths and projects still exist' do
+ expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_truthy
+ expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey
+ expect(Project.unscoped.count).to eq(1)
+ expect(Group.unscoped.count).to eq(2)
+ end
+ end
+
context 'potential race conditions' do
context "when the `GroupDestroyWorker` task runs immediately" do
it "deletes the group" do
@@ -88,7 +110,7 @@ describe Groups::DestroyService, services: true do
# Kick off the initial group destroy in a new thread, so that
# it doesn't share this spec's database transaction.
- Thread.new { Groups::DestroyService.new(group, user).async_execute }.join(5)
+ Thread.new { described_class.new(group, user).async_execute }.join(5)
group_record = run_with_new_database_connection do |conn|
conn.execute("SELECT * FROM namespaces WHERE id = #{group.id}").first
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index f6ad5cebd2c..9902e1aff8b 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Groups::UpdateService, services: true do
+describe Groups::UpdateService do
let!(:user) { create(:user) }
let!(:private_group) { create(:group, :private) }
let!(:internal_group) { create(:group, :internal) }
diff --git a/spec/services/import_export_clean_up_service_spec.rb b/spec/services/import_export_clean_up_service_spec.rb
index 81b1d327696..1875d0448cd 100644
--- a/spec/services/import_export_clean_up_service_spec.rb
+++ b/spec/services/import_export_clean_up_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ImportExportCleanUpService, services: true do
+describe ImportExportCleanUpService do
describe '#execute' do
let(:service) { described_class.new }
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index eb9b1670c71..055aa6156cb 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issuable::BulkUpdateService, services: true do
+describe Issuable::BulkUpdateService do
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace) }
diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb
index bed25fe7ccf..03f76bd428d 100644
--- a/spec/services/issues/build_service_spec.rb
+++ b/spec/services/issues/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper.rb'
-describe Issues::BuildService, services: true do
+describe Issues::BuildService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index d6f4c694069..a03f68434de 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::CloseService, services: true do
+describe Issues::CloseService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
@@ -98,13 +98,13 @@ describe Issues::CloseService, services: true do
end
end
- context 'external issue tracker' do
+ context 'internal issues disabled' do
before do
- allow(project).to receive(:default_issues_tracker?).and_return(false)
- described_class.new(project, user).close_issue(issue)
+ project.issues_enabled = false
+ project.save!
end
- it 'closes the issue' do
+ it 'does not close the issue' do
expect(issue).to be_valid
expect(issue).to be_opened
expect(todo.reload).to be_pending
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index ae9d2b2855d..a48748e274d 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::CreateService, services: true do
+describe Issues::CreateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb
new file mode 100644
index 00000000000..ed55664e382
--- /dev/null
+++ b/spec/services/issues/duplicate_service_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe Issues::DuplicateService do
+ let(:user) { create(:user) }
+ let(:canonical_project) { create(:empty_project) }
+ let(:duplicate_project) { create(:empty_project) }
+
+ let(:canonical_issue) { create(:issue, project: canonical_project) }
+ let(:duplicate_issue) { create(:issue, project: duplicate_project) }
+
+ subject { described_class.new(duplicate_project, user, {}) }
+
+ describe '#execute' do
+ context 'when the issues passed are the same' do
+ it 'does nothing' do
+ expect(subject).not_to receive(:close_service)
+ expect(SystemNoteService).not_to receive(:mark_duplicate_issue)
+ expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate)
+
+ subject.execute(duplicate_issue, duplicate_issue)
+ end
+ end
+
+ context 'when the user cannot update the duplicate issue' do
+ before do
+ canonical_project.add_reporter(user)
+ end
+
+ it 'does nothing' do
+ expect(subject).not_to receive(:close_service)
+ expect(SystemNoteService).not_to receive(:mark_duplicate_issue)
+ expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+ end
+
+ context 'when the user cannot comment on the canonical issue' do
+ before do
+ duplicate_project.add_reporter(user)
+ end
+
+ it 'does nothing' do
+ expect(subject).not_to receive(:close_service)
+ expect(SystemNoteService).not_to receive(:mark_duplicate_issue)
+ expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+ end
+
+ context 'when the user can mark the issue as a duplicate' do
+ before do
+ canonical_project.add_reporter(user)
+ duplicate_project.add_reporter(user)
+ end
+
+ it 'closes the duplicate issue' do
+ subject.execute(duplicate_issue, canonical_issue)
+
+ expect(duplicate_issue.reload).to be_closed
+ expect(canonical_issue.reload).to be_open
+ end
+
+ it 'adds a system note to the duplicate issue' do
+ expect(SystemNoteService)
+ .to receive(:mark_duplicate_issue).with(duplicate_issue, duplicate_project, user, canonical_issue)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+
+ it 'adds a system note to the canonical issue' do
+ expect(SystemNoteService)
+ .to receive(:mark_canonical_issue_of_duplicate).with(canonical_issue, canonical_project, user, duplicate_issue)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+ end
+ end
+end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index d1dd1466d95..171fc7334c4 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::MoveService, services: true do
+describe Issues::MoveService do
let(:user) { create(:user) }
let(:author) { create(:user) }
let(:title) { 'Some issue' }
@@ -37,9 +37,6 @@ describe Issues::MoveService, services: true do
describe '#execute' do
shared_context 'issue move executed' do
- let!(:milestone2) do
- create(:milestone, project_id: new_project.id, title: 'v9.0')
- end
let!(:award_emoji) { create(:award_emoji, awardable: old_issue) }
let!(:new_issue) { move_service.execute(old_issue, new_project) }
@@ -48,6 +45,63 @@ describe Issues::MoveService, services: true do
context 'issue movable' do
include_context 'user can move issue'
+ context 'move to new milestone' do
+ let(:new_issue) { move_service.execute(old_issue, new_project) }
+
+ context 'project milestone' do
+ let!(:milestone2) do
+ create(:milestone, project_id: new_project.id, title: 'v9.0')
+ end
+
+ it 'assigns milestone to new issue' do
+ expect(new_issue.reload.milestone.title).to eq 'v9.0'
+ expect(new_issue.reload.milestone).to eq(milestone2)
+ end
+ end
+
+ context 'group milestones' do
+ let!(:group) { create(:group, :private) }
+ let!(:group_milestone_1) do
+ create(:milestone, group_id: group.id, title: 'v9.0_group')
+ end
+
+ before do
+ old_issue.update(milestone: group_milestone_1)
+ old_project.update(namespace: group)
+ new_project.update(namespace: group)
+
+ group.add_users([user], GroupMember::DEVELOPER)
+ end
+
+ context 'when moving to a project of the same group' do
+ it 'keeps the same group milestone' do
+ expect(new_issue.reload.project).to eq(new_project)
+ expect(new_issue.reload.milestone).to eq(group_milestone_1)
+ end
+ end
+
+ context 'when moving to a project of a different group' do
+ let!(:group_2) { create(:group, :private) }
+
+ let!(:group_milestone_2) do
+ create(:milestone, group_id: group_2.id, title: 'v9.0_group')
+ end
+
+ before do
+ old_issue.update(milestone: group_milestone_1)
+ new_project.update(namespace: group_2)
+
+ group_2.add_users([user], GroupMember::DEVELOPER)
+ end
+
+ it 'assigns to new group milestone of same title' do
+ expect(new_issue.reload.project).to eq(new_project)
+ expect(new_issue.reload.milestone).to eq(group_milestone_2)
+ end
+ end
+ end
+ end
+
context 'generic issue' do
include_context 'issue move executed'
@@ -55,11 +109,6 @@ describe Issues::MoveService, services: true do
expect(new_issue.project).to eq new_project
end
- it 'assigns milestone to new issue' do
- expect(new_issue.reload.milestone.title).to eq 'v9.0'
- expect(new_issue.reload.milestone).to eq(milestone2)
- end
-
it 'assign labels to new issue' do
expected_label_titles = new_issue.reload.labels.map(&:title)
expect(expected_label_titles).to include 'label1'
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 391ecad303a..1ff988e9b47 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::ReopenService, services: true do
+describe Issues::ReopenService do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, :closed, project: project) }
diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb
index 86f218dec12..fac66791ffb 100644
--- a/spec/services/issues/resolve_discussions_spec.rb
+++ b/spec/services/issues/resolve_discussions_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper.rb'
-describe Issues::ResolveDiscussions, services: true do
+describe Issues::ResolveDiscussions do
class DummyService < Issues::BaseService
include ::Issues::ResolveDiscussions
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index c26642f5015..eec2096fa34 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -1,7 +1,7 @@
# coding: utf-8
require 'spec_helper'
-describe Issues::UpdateService, services: true do
+describe Issues::UpdateService do
include EmailHelpers
let(:user) { create(:user) }
@@ -253,13 +253,13 @@ describe Issues::UpdateService, services: true do
end
context 'when the milestone change' do
- before do
+ it 'marks todos as done' do
update_issue(milestone: create(:milestone))
- end
- it 'marks todos as done' do
expect(todo.reload.done?).to eq true
end
+
+ it_behaves_like 'system notes for milestones'
end
context 'when the labels change' do
@@ -488,7 +488,28 @@ describe Issues::UpdateService, services: true do
context 'updating mentions' do
let(:mentionable) { issue }
- include_examples 'updating mentions', Issues::UpdateService
+ include_examples 'updating mentions', described_class
+ end
+
+ context 'duplicate issue' do
+ let(:canonical_issue) { create(:issue, project: project) }
+
+ context 'invalid canonical_issue_id' do
+ it 'does not call the duplicate service' do
+ expect(Issues::DuplicateService).not_to receive(:new)
+
+ update_issue(canonical_issue_id: 123456789)
+ end
+ end
+
+ context 'valid canonical_issue_id' do
+ it 'calls the duplicate service with both issues' do
+ expect_any_instance_of(Issues::DuplicateService)
+ .to receive(:execute).with(issue, canonical_issue)
+
+ update_issue(canonical_issue_id: canonical_issue.id)
+ end
+ end
end
include_examples 'issuable update service' do
diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb
index 0ecab0c3475..ecb88653001 100644
--- a/spec/services/labels/create_service_spec.rb
+++ b/spec/services/labels/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Labels::CreateService, services: true do
+describe Labels::CreateService do
describe '#execute' do
let(:project) { create(:project) }
let(:group) { create(:group) }
@@ -17,7 +17,7 @@ describe Labels::CreateService, services: true do
context 'in a project' do
context 'with color in hex-code' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(hex_color)).execute(project: project)
+ label = described_class.new(params_with(hex_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -26,7 +26,7 @@ describe Labels::CreateService, services: true do
context 'with color in allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(named_color)).execute(project: project)
+ label = described_class.new(params_with(named_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -35,7 +35,7 @@ describe Labels::CreateService, services: true do
context 'with color in up-case allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(upcase_color)).execute(project: project)
+ label = described_class.new(params_with(upcase_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -44,7 +44,7 @@ describe Labels::CreateService, services: true do
context 'with color surrounded by spaces' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(spaced_color)).execute(project: project)
+ label = described_class.new(params_with(spaced_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -53,7 +53,7 @@ describe Labels::CreateService, services: true do
context 'with unknown color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(unknown_color)).execute(project: project)
+ label = described_class.new(params_with(unknown_color)).execute(project: project)
expect(label).not_to be_persisted
end
@@ -61,7 +61,7 @@ describe Labels::CreateService, services: true do
context 'with no color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(no_color)).execute(project: project)
+ label = described_class.new(params_with(no_color)).execute(project: project)
expect(label).not_to be_persisted
end
@@ -71,7 +71,7 @@ describe Labels::CreateService, services: true do
context 'in a group' do
context 'with color in hex-code' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(hex_color)).execute(group: group)
+ label = described_class.new(params_with(hex_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -80,7 +80,7 @@ describe Labels::CreateService, services: true do
context 'with color in allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(named_color)).execute(group: group)
+ label = described_class.new(params_with(named_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -89,7 +89,7 @@ describe Labels::CreateService, services: true do
context 'with color in up-case allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(upcase_color)).execute(group: group)
+ label = described_class.new(params_with(upcase_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -98,7 +98,7 @@ describe Labels::CreateService, services: true do
context 'with color surrounded by spaces' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(spaced_color)).execute(group: group)
+ label = described_class.new(params_with(spaced_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -107,7 +107,7 @@ describe Labels::CreateService, services: true do
context 'with unknown color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(unknown_color)).execute(group: group)
+ label = described_class.new(params_with(unknown_color)).execute(group: group)
expect(label).not_to be_persisted
end
@@ -115,7 +115,7 @@ describe Labels::CreateService, services: true do
context 'with no color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(no_color)).execute(group: group)
+ label = described_class.new(params_with(no_color)).execute(group: group)
expect(label).not_to be_persisted
end
@@ -125,7 +125,7 @@ describe Labels::CreateService, services: true do
context 'in admin area' do
context 'with color in hex-code' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(hex_color)).execute(template: true)
+ label = described_class.new(params_with(hex_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -134,7 +134,7 @@ describe Labels::CreateService, services: true do
context 'with color in allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(named_color)).execute(template: true)
+ label = described_class.new(params_with(named_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -143,7 +143,7 @@ describe Labels::CreateService, services: true do
context 'with color in up-case allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(upcase_color)).execute(template: true)
+ label = described_class.new(params_with(upcase_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -152,7 +152,7 @@ describe Labels::CreateService, services: true do
context 'with color surrounded by spaces' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(spaced_color)).execute(template: true)
+ label = described_class.new(params_with(spaced_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -161,7 +161,7 @@ describe Labels::CreateService, services: true do
context 'with unknown color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(unknown_color)).execute(template: true)
+ label = described_class.new(params_with(unknown_color)).execute(template: true)
expect(label).not_to be_persisted
end
@@ -169,7 +169,7 @@ describe Labels::CreateService, services: true do
context 'with no color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(no_color)).execute(template: true)
+ label = described_class.new(params_with(no_color)).execute(template: true)
expect(label).not_to be_persisted
end
diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb
index de8f1827cce..2d3a15a1c11 100644
--- a/spec/services/labels/find_or_create_service_spec.rb
+++ b/spec/services/labels/find_or_create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Labels::FindOrCreateService, services: true do
+describe Labels::FindOrCreateService do
describe '#execute' do
let(:group) { create(:group) }
let(:project) { create(:empty_project, namespace: group) }
diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb
index 500afdfb916..7cea877ad88 100644
--- a/spec/services/labels/promote_service_spec.rb
+++ b/spec/services/labels/promote_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Labels::PromoteService, services: true do
+describe Labels::PromoteService do
describe '#execute' do
let!(:user) { create(:user) }
diff --git a/spec/services/labels/transfer_service_spec.rb b/spec/services/labels/transfer_service_spec.rb
index 11d5f1cad5e..f70edd3d16e 100644
--- a/spec/services/labels/transfer_service_spec.rb
+++ b/spec/services/labels/transfer_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Labels::TransferService, services: true do
+describe Labels::TransferService do
describe '#execute' do
let(:user) { create(:admin) }
let(:group_1) { create(:group) }
diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb
index f2498ea6990..bb95fe20fbf 100644
--- a/spec/services/labels/update_service_spec.rb
+++ b/spec/services/labels/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Labels::UpdateService, services: true do
+describe Labels::UpdateService do
describe '#execute' do
let(:project) { create(:project) }
@@ -20,7 +20,7 @@ describe Labels::UpdateService, services: true do
context 'with color in hex-code' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(hex_color)).execute(@label)
+ label = described_class.new(params_with(hex_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -29,7 +29,7 @@ describe Labels::UpdateService, services: true do
context 'with color in allowed name' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(named_color)).execute(@label)
+ label = described_class.new(params_with(named_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -38,7 +38,7 @@ describe Labels::UpdateService, services: true do
context 'with color in up-case allowed name' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(upcase_color)).execute(@label)
+ label = described_class.new(params_with(upcase_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -47,7 +47,7 @@ describe Labels::UpdateService, services: true do
context 'with color surrounded by spaces' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(spaced_color)).execute(@label)
+ label = described_class.new(params_with(spaced_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -56,7 +56,7 @@ describe Labels::UpdateService, services: true do
context 'with unknown color' do
it 'doesn\'t update the label' do
- label = Labels::UpdateService.new(params_with(unknown_color)).execute(@label)
+ label = described_class.new(params_with(unknown_color)).execute(@label)
expect(label).not_to be_valid
end
@@ -64,7 +64,7 @@ describe Labels::UpdateService, services: true do
context 'with no color' do
it 'doesn\'t update the label' do
- label = Labels::UpdateService.new(params_with(no_color)).execute(@label)
+ label = described_class.new(params_with(no_color)).execute(@label)
expect(label).not_to be_valid
end
diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb
index 7d5a66801db..ddba96b8d03 100644
--- a/spec/services/members/approve_access_request_service_spec.rb
+++ b/spec/services/members/approve_access_request_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Members::ApproveAccessRequestService, services: true do
+describe Members::ApproveAccessRequestService do
let(:user) { create(:user) }
let(:access_requester) { create(:user) }
let(:project) { create(:empty_project, :public, :access_requestable) }
diff --git a/spec/services/members/authorized_destroy_service_spec.rb b/spec/services/members/authorized_destroy_service_spec.rb
index f99b11f208c..f0abbc46ca3 100644
--- a/spec/services/members/authorized_destroy_service_spec.rb
+++ b/spec/services/members/authorized_destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Members::AuthorizedDestroyService, services: true do
+describe Members::AuthorizedDestroyService do
let(:member_user) { create(:user) }
let(:project) { create(:empty_project, :public) }
let(:group) { create(:group, :public) }
diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb
index 5a05ab3ea50..c73a229823d 100644
--- a/spec/services/members/create_service_spec.rb
+++ b/spec/services/members/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Members::CreateService, services: true do
+describe Members::CreateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:project_user) { create(:user) }
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 9ab7839430c..0e30b343eaf 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Members::DestroyService, services: true do
+describe Members::DestroyService do
let(:user) { create(:user) }
let(:member_user) { create(:user) }
let(:project) { create(:empty_project, :public) }
diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb
index 814c17b9ad0..f39d4f47904 100644
--- a/spec/services/members/request_access_service_spec.rb
+++ b/spec/services/members/request_access_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Members::RequestAccessService, services: true do
+describe Members::RequestAccessService do
let(:user) { create(:user) }
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb
index d3556020d4d..fcbe0e5985f 100644
--- a/spec/services/merge_requests/assign_issues_service_spec.rb
+++ b/spec/services/merge_requests/assign_issues_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::AssignIssuesService, services: true do
+describe MergeRequests::AssignIssuesService do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 01ef52396d7..ea192e51f89 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::BuildService, services: true do
+describe MergeRequests::BuildService do
include RepoHelpers
let(:project) { create(:project, :repository) }
@@ -19,7 +19,7 @@ describe MergeRequests::BuildService, services: true do
let(:commits) { nil }
let(:service) do
- MergeRequests::BuildService.new(project, user,
+ described_class.new(project, user,
description: description,
source_branch: source_branch,
target_branch: target_branch,
@@ -207,7 +207,7 @@ describe MergeRequests::BuildService, services: true do
let(:source_branch) { '12345-fix-issue' }
before do
- allow(project).to receive(:default_issues_tracker?).and_return(false)
+ allow(project).to receive(:external_issue_tracker).and_return(true)
end
it 'sets the title to: Resolves External Issue $issue-iid' do
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index 074d4672b06..04bf267d167 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CloseService, services: true do
+describe MergeRequests::CloseService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb
index 1588d30c394..492b55cdece 100644
--- a/spec/services/merge_requests/create_from_issue_service_spec.rb
+++ b/spec/services/merge_requests/create_from_issue_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CreateFromIssueService, services: true do
+describe MergeRequests::CreateFromIssueService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 36a2b672473..8fef480274d 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CreateService, services: true do
+describe MergeRequests::CreateService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:assignee) { create(:user) }
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
index 4a7d8ab4c6c..672d86e4028 100644
--- a/spec/services/merge_requests/get_urls_service_spec.rb
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -78,7 +78,7 @@ describe MergeRequests::GetUrlsService do
end
context 'pushing to existing branch and merge request is reopened' do
- let!(:merge_request) { create(:merge_request, :reopened, source_project: project, source_branch: source_branch) }
+ let!(:merge_request) { create(:merge_request, :opened, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
it_behaves_like 'show_merge_request_url'
end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 711059208c1..e593bfeeaf7 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe MergeRequests::MergeService, services: true do
+describe MergeRequests::MergeService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
- let(:merge_request) { create(:merge_request, assignee: user2) }
+ let(:merge_request) { create(:merge_request, :simple, author: user2, assignee: user2) }
let(:project) { merge_request.project }
before do
@@ -13,7 +13,7 @@ describe MergeRequests::MergeService, services: true do
describe '#execute' do
context 'valid params' do
- let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
before do
allow(service).to receive(:execute_hooks)
@@ -112,7 +112,7 @@ describe MergeRequests::MergeService, services: true do
context 'closes related todos' do
let(:merge_request) { create(:merge_request, assignee: user, author: user) }
let(:project) { merge_request.project }
- let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
let!(:todo) do
create(:todo, :assigned,
project: project,
@@ -133,23 +133,70 @@ describe MergeRequests::MergeService, services: true do
it { expect(todo).to be_done }
end
- context 'remove source branch by author' do
- let(:service) do
- merge_request.merge_params['force_remove_source_branch'] = '1'
- merge_request.save!
- MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message')
+ context 'source branch removal' do
+ context 'when the source branch is protected' do
+ let(:service) do
+ described_class.new(project, user, should_remove_source_branch: '1')
+ end
+
+ before do
+ create(:protected_branch, project: project, name: merge_request.source_branch)
+ end
+
+ it 'does not delete the source branch' do
+ expect(DeleteBranchService).not_to receive(:new)
+ service.execute(merge_request)
+ end
end
- it 'removes the source branch' do
- expect(DeleteBranchService).to receive(:new)
- .with(merge_request.source_project, merge_request.author)
- .and_call_original
- service.execute(merge_request)
+ context 'when the source branch is the default branch' do
+ let(:service) do
+ described_class.new(project, user, should_remove_source_branch: '1')
+ end
+
+ before do
+ allow(project).to receive(:root_ref?).with(merge_request.source_branch).and_return(true)
+ end
+
+ it 'does not delete the source branch' do
+ expect(DeleteBranchService).not_to receive(:new)
+ service.execute(merge_request)
+ end
+ end
+
+ context 'when the source branch can be removed' do
+ context 'when MR author set the source branch to be removed' do
+ let(:service) do
+ merge_request.merge_params['force_remove_source_branch'] = '1'
+ merge_request.save!
+ described_class.new(project, user, commit_message: 'Awesome message')
+ end
+
+ it 'removes the source branch using the author user' do
+ expect(DeleteBranchService).to receive(:new)
+ .with(merge_request.source_project, merge_request.author)
+ .and_call_original
+ service.execute(merge_request)
+ end
+ end
+
+ context 'when MR merger set the source branch to be removed' do
+ let(:service) do
+ described_class.new(project, user, commit_message: 'Awesome message', should_remove_source_branch: '1')
+ end
+
+ it 'removes the source branch using the current user' do
+ expect(DeleteBranchService).to receive(:new)
+ .with(merge_request.source_project, user)
+ .and_call_original
+ service.execute(merge_request)
+ end
+ end
end
end
context "error handling" do
- let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
before do
allow(Rails.logger).to receive(:error)
diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb
index a20b32eda5f..a37cdab8928 100644
--- a/spec/services/merge_requests/post_merge_service_spec.rb
+++ b/spec/services/merge_requests/post_merge_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::PostMergeService, services: true do
+describe MergeRequests::PostMergeService do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 671a932441e..2af2485eeed 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe MergeRequests::RefreshService, services: true do
+describe MergeRequests::RefreshService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
- let(:service) { MergeRequests::RefreshService }
+ let(:service) { described_class }
describe '#execute' do
before do
@@ -98,18 +98,52 @@ describe MergeRequests::RefreshService, services: true do
end
context 'push to origin repo target branch' do
- before do
- service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
- reload_mrs
+ context 'when all MRs to the target branch had diffs' do
+ before do
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
+ end
+
+ it 'updates the merge state' do
+ expect(@merge_request.notes.last.note).to include('merged')
+ expect(@merge_request).to be_merged
+ expect(@fork_merge_request).to be_merged
+ expect(@fork_merge_request.notes.last.note).to include('merged')
+ expect(@build_failed_todo).to be_done
+ expect(@fork_build_failed_todo).to be_done
+ end
end
- it 'updates the merge state' do
- expect(@merge_request.notes.last.note).to include('merged')
- expect(@merge_request).to be_merged
- expect(@fork_merge_request).to be_merged
- expect(@fork_merge_request.notes.last.note).to include('merged')
- expect(@build_failed_todo).to be_done
- expect(@fork_build_failed_todo).to be_done
+ context 'when an MR to be closed was empty already' do
+ let!(:empty_fork_merge_request) do
+ create(:merge_request,
+ source_project: @fork_project,
+ source_branch: 'master',
+ target_branch: 'master',
+ target_project: @project)
+ end
+
+ before do
+ # This spec already has a fake push, so pretend that we were targeting
+ # feature all along.
+ empty_fork_merge_request.update_columns(target_branch: 'feature')
+
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
+ empty_fork_merge_request.reload
+ end
+
+ it 'only updates the non-empty MRs' do
+ expect(@merge_request).to be_merged
+ expect(@merge_request.notes.last.note).to include('merged')
+
+ expect(@fork_merge_request).to be_merged
+ expect(@fork_merge_request.notes.last.note).to include('merged')
+
+ expect(empty_fork_merge_request).to be_open
+ expect(empty_fork_merge_request.merge_request_diff.state).to eq('empty')
+ expect(empty_fork_merge_request.notes).to be_empty
+ end
end
end
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index 6cc403bdb7f..f02af0c582e 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::ReopenService, services: true do
+describe MergeRequests::ReopenService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
@@ -28,7 +28,7 @@ describe MergeRequests::ReopenService, services: true do
end
it { expect(merge_request).to be_valid }
- it { expect(merge_request).to be_reopened }
+ it { expect(merge_request).to be_opened }
it 'executes hooks with reopen action' do
expect(service).to have_received(:execute_hooks)
diff --git a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
index 7ddd812e513..e3fd906fe7b 100644
--- a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
+++ b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::ResolvedDiscussionNotificationService, services: true do
+describe MergeRequests::ResolvedDiscussionNotificationService do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index ec15b5cac14..dd3ac9c4ac6 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::UpdateService, services: true do
+describe MergeRequests::UpdateService do
include EmailHelpers
let(:project) { create(:project, :repository) }
@@ -55,7 +55,7 @@ describe MergeRequests::UpdateService, services: true do
}
end
- let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
+ let(:service) { described_class.new(project, user, opts) }
before do
allow(service).to receive(:execute_hooks)
@@ -145,7 +145,7 @@ describe MergeRequests::UpdateService, services: true do
}
end
- let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
+ let(:service) { described_class.new(project, user, opts) }
context 'without pipeline' do
before do
@@ -205,7 +205,7 @@ describe MergeRequests::UpdateService, services: true do
context 'with a non-authorised user' do
let(:visitor) { create(:user) }
- let(:service) { MergeRequests::UpdateService.new(project, visitor, opts) }
+ let(:service) { described_class.new(project, visitor, opts) }
before do
merge_request.update_attribute(:merge_error, 'Error')
@@ -296,13 +296,13 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when the milestone change' do
- before do
+ it 'marks pending todos as done' do
update_merge_request({ milestone: create(:milestone) })
- end
- it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
end
+
+ it_behaves_like 'system notes for milestones'
end
context 'when the labels change' do
@@ -348,7 +348,7 @@ describe MergeRequests::UpdateService, services: true do
opts = { label_ids: [label.id] }
perform_enqueued_jobs do
- @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request = described_class.new(project, user, opts).execute(merge_request)
end
should_email(subscriber)
@@ -364,7 +364,7 @@ describe MergeRequests::UpdateService, services: true do
opts = { label_ids: [label.id, label2.id] }
perform_enqueued_jobs do
- @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request = described_class.new(project, user, opts).execute(merge_request)
end
should_not_email(subscriber)
@@ -375,7 +375,7 @@ describe MergeRequests::UpdateService, services: true do
opts = { label_ids: [label2.id] }
perform_enqueued_jobs do
- @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request = described_class.new(project, user, opts).execute(merge_request)
end
should_not_email(subscriber)
@@ -386,7 +386,7 @@ describe MergeRequests::UpdateService, services: true do
context 'updating mentions' do
let(:mentionable) { merge_request }
- include_examples 'updating mentions', MergeRequests::UpdateService
+ include_examples 'updating mentions', described_class
end
context 'when MergeRequest has tasks' do
diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb
index d581b94ff43..fa0686d8061 100644
--- a/spec/services/milestones/close_service_spec.rb
+++ b/spec/services/milestones/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Milestones::CloseService, services: true do
+describe Milestones::CloseService do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) }
@@ -11,7 +11,7 @@ describe Milestones::CloseService, services: true do
describe '#execute' do
before do
- Milestones::CloseService.new(project, user, {}).execute(milestone)
+ described_class.new(project, user, {}).execute(milestone)
end
it { expect(milestone).to be_valid }
diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb
index 6d29edb449a..c6fe8e65912 100644
--- a/spec/services/milestones/create_service_spec.rb
+++ b/spec/services/milestones/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Milestones::CreateService, services: true do
+describe Milestones::CreateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -14,7 +14,7 @@ describe Milestones::CreateService, services: true do
description: 'Patch release to fix security issue'
}
- @milestone = Milestones::CreateService.new(project, user, opts).execute
+ @milestone = described_class.new(project, user, opts).execute
end
it { expect(@milestone).to be_valid }
diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb
new file mode 100644
index 00000000000..5739386dd0d
--- /dev/null
+++ b/spec/services/milestones/destroy_service_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe Milestones::DestroyService do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) }
+ let(:issue) { create(:issue, project: project, milestone: milestone) }
+ let(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ def service
+ described_class.new(project, user, {})
+ end
+
+ describe '#execute' do
+ it 'deletes milestone' do
+ service.execute(milestone)
+
+ expect { milestone.reload }.to raise_error ActiveRecord::RecordNotFound
+ end
+
+ it 'deletes milestone id from issuables' do
+ service.execute(milestone)
+
+ expect(issue.reload.milestone).to be_nil
+ expect(merge_request.reload.milestone).to be_nil
+ end
+
+ context 'group milestones' do
+ let(:group) { create(:group) }
+ let(:group_milestone) { create(:milestone, group: group) }
+
+ before do
+ project.update(namespace: group)
+ group.add_developer(user)
+ end
+
+ it { expect(service.execute(group_milestone)).to be_nil }
+
+ it 'does not update milestone issuables' do
+ expect(MergeRequests::UpdateService).not_to receive(:new)
+ expect(Issues::UpdateService).not_to receive(:new)
+
+ service.execute(group_milestone)
+ end
+ end
+ end
+end
diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb
index 39f06f8f8e7..dda579c7080 100644
--- a/spec/services/note_summary_spec.rb
+++ b/spec/services/note_summary_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe NoteSummary, services: true do
+describe NoteSummary do
let(:project) { build(:empty_project) }
let(:noteable) { build(:issue) }
let(:user) { build(:user) }
diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb
index 133175769ca..6e1c1fe6c02 100644
--- a/spec/services/notes/build_service_spec.rb
+++ b/spec/services/notes/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::BuildService, services: true do
+describe Notes::BuildService do
let(:note) { create(:discussion_note_on_issue) }
let(:project) { note.project }
let(:author) { note.author }
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 152c6d20daa..c08a5a940bb 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::CreateService, services: true do
+describe Notes::CreateService do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb
index f53f96e0c2b..4330190caaa 100644
--- a/spec/services/notes/destroy_service_spec.rb
+++ b/spec/services/notes/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::DestroyService, services: true do
+describe Notes::DestroyService do
describe '#execute' do
it 'deletes a note' do
project = create(:empty_project)
diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb
index e33a611929b..bf9320e5fce 100644
--- a/spec/services/notes/post_process_service_spec.rb
+++ b/spec/services/notes/post_process_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::PostProcessService, services: true do
+describe Notes::PostProcessService do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
@@ -21,7 +21,7 @@ describe Notes::PostProcessService, services: true do
expect(project).to receive(:execute_hooks)
expect(project).to receive(:execute_services)
- Notes::PostProcessService.new(@note).execute
+ described_class.new(@note).execute
end
end
end
diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb
index 9a98499826f..fc4cd3dc2b7 100644
--- a/spec/services/notes/quick_actions_service_spec.rb
+++ b/spec/services/notes/quick_actions_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::QuickActionsService, services: true do
+describe Notes::QuickActionsService do
shared_context 'note on noteable' do
let(:project) { create(:empty_project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index 905e2f46bde..dea2dc02d00 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::UpdateService, services: true do
+describe Notes::UpdateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
diff --git a/spec/services/notification_recipient_service_spec.rb b/spec/services/notification_recipient_service_spec.rb
new file mode 100644
index 00000000000..77233dc1b2f
--- /dev/null
+++ b/spec/services/notification_recipient_service_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe NotificationRecipientService do
+ set(:user) { create(:user) }
+ set(:project) { create(:empty_project, :public) }
+ set(:issue) { create(:issue, project: project) }
+
+ set(:watcher) do
+ watcher = create(:user)
+ setting = watcher.notification_settings_for(project)
+ setting.level = :watch
+ setting.save
+
+ watcher
+ end
+
+ subject { described_class.new(project) }
+
+ describe '#build_recipients' do
+ it 'does not modify the participants of the target' do
+ expect { subject.build_recipients(issue, user, action: :new_issue) }
+ .not_to change { issue.participants(user) }
+ end
+ end
+
+ describe '#build_new_note_recipients' do
+ set(:note) { create(:note_on_issue, noteable: issue, project: project) }
+
+ it 'does not modify the participants of the target' do
+ expect { subject.build_new_note_recipients(note) }
+ .not_to change { note.noteable.participants(note.author) }
+ end
+ end
+end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index f1e00c1163b..5b69426cbaa 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe NotificationService, services: true do
+describe NotificationService do
include EmailHelpers
- let(:notification) { NotificationService.new }
+ let(:notification) { described_class.new }
let(:assignee) { create(:user) }
around(:each) do |example|
@@ -93,6 +93,18 @@ describe NotificationService, services: true do
end
end
+ describe 'GpgKeys' do
+ describe '#new_gpg_key' do
+ let!(:key) { create(:gpg_key) }
+
+ it { expect(notification.new_gpg_key(key)).to be_truthy }
+
+ it 'sends email to key owner' do
+ expect{ notification.new_gpg_key(key) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
+ end
+ end
+ end
+
describe 'Email' do
describe '#new_email' do
let!(:email) { create(:email) }
@@ -383,7 +395,7 @@ describe NotificationService, services: true do
before do
build_team(note.project)
reset_delivered_emails!
- allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer)
+ allow(note.noteable).to receive(:author).and_return(@u_committer)
update_custom_notification(:new_note, @u_guest_custom, resource: project)
update_custom_notification(:new_note, @u_custom_global)
end
@@ -682,17 +694,6 @@ describe NotificationService, services: true do
let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } }
let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } }
- it "emails subscribers of the issue's added labels only" do
- notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
-
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
- end
-
it "emails the current user if they've opted into notifications about their activity" do
subscriber_to_label_2.notified_of_own_activity = true
notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2)
@@ -709,6 +710,12 @@ describe NotificationService, services: true do
it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
+ should_not_email(subscriber_to_label_1)
+ should_not_email(subscriber_to_group_label_1)
+ should_not_email(subscriber_to_group_label_2_on_another_project)
+ should_email(subscriber_1_to_group_label_2)
+ should_email(subscriber_2_to_group_label_2)
+ should_email(subscriber_to_label_2)
should_not_email(issue.assignees.first)
should_not_email(issue.author)
should_not_email(@u_watcher)
@@ -718,12 +725,6 @@ describe NotificationService, services: true do
should_not_email(@watcher_and_subscriber)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
end
context 'confidential issues' do
@@ -866,11 +867,6 @@ describe NotificationService, services: true do
end
describe '#new_merge_request' do
- before do
- update_custom_notification(:new_merge_request, @u_guest_custom, resource: project)
- update_custom_notification(:new_merge_request, @u_custom_global)
- end
-
it do
notification.new_merge_request(merge_request, @u_disabled)
@@ -996,7 +992,7 @@ describe NotificationService, services: true do
let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } }
let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } }
- it "emails subscribers of the merge request's added labels only" do
+ it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled)
should_not_email(subscriber_to_label_1)
@@ -1005,11 +1001,6 @@ describe NotificationService, services: true do
should_email(subscriber_1_to_group_label_2)
should_email(subscriber_2_to_group_label_2)
should_email(subscriber_to_label_2)
- end
-
- it "doesn't send email to anyone but subscribers of the given labels" do
- notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled)
-
should_not_email(merge_request.assignee)
should_not_email(merge_request.author)
should_not_email(@u_watcher)
@@ -1019,12 +1010,6 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_lazy_participant)
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
end
end
@@ -1069,12 +1054,12 @@ describe NotificationService, services: true do
should_email(merge_request.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
+ should_email(@u_guest_custom)
+ should_email(@u_custom_global)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
- should_email(@u_guest_watcher)
- should_email(@u_custom_global)
- should_email(@u_guest_custom)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb
index cf38c7c75e5..f8db6900a0a 100644
--- a/spec/services/pages_service_spec.rb
+++ b/spec/services/pages_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe PagesService, services: true do
+describe PagesService do
let(:build) { create(:ci_build) }
let(:data) { Gitlab::DataBuilder::Build.build(build) }
- let(:service) { PagesService.new(data) }
+ let(:service) { described_class.new(data) }
before do
allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
index c198c3eedfc..fc7238862ab 100644
--- a/spec/services/projects/autocomplete_service_spec.rb
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::AutocompleteService, services: true do
+describe Projects::AutocompleteService do
describe '#issues' do
describe 'confidential issues' do
let(:author) { create(:user) }
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 40298dcb723..b0dc7488b5f 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::CreateService, '#execute', services: true do
+describe Projects::CreateService, '#execute' do
let(:user) { create :user }
let(:opts) do
{
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index 0d6dd28e332..85b05ef6d05 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::DestroyService, services: true do
+describe Projects::DestroyService do
let!(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace) }
let!(:path) { project.repository.path_to_repo }
@@ -15,8 +15,9 @@ describe Projects::DestroyService, services: true do
shared_examples 'deleting the project' do
it 'deletes the project' do
expect(Project.unscoped.all).not_to include(project)
- expect(Dir.exist?(path)).to be_falsey
- expect(Dir.exist?(remove_path)).to be_falsey
+
+ expect(project.gitlab_shell.exists?(project.repository_storage_path, path + '.git')).to be_falsey
+ expect(project.gitlab_shell.exists?(project.repository_storage_path, remove_path + '.git')).to be_falsey
end
end
@@ -35,6 +36,27 @@ describe Projects::DestroyService, services: true do
end
end
+ shared_examples 'handles errors thrown during async destroy' do |error_message|
+ it 'does not allow the error to bubble up' do
+ expect do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+ end.not_to raise_error
+ end
+
+ it 'unmarks the project as "pending deletion"' do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+
+ expect(project.reload.pending_delete).to be(false)
+ end
+
+ it 'stores an error message in `projects.delete_error`' do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+
+ expect(project.reload.delete_error).to be_present
+ expect(project.delete_error).to include(error_message)
+ end
+ end
+
context 'Sidekiq inline' do
before do
# Run sidekiq immediatly to check that renamed repository will be removed
@@ -59,14 +81,14 @@ describe Projects::DestroyService, services: true do
before do
new_user = create(:user)
project.team.add_user(new_user, Gitlab::Access::DEVELOPER)
- allow_any_instance_of(Projects::DestroyService).to receive(:flush_caches).and_raise(Redis::CannotConnectError)
+ allow_any_instance_of(described_class).to receive(:flush_caches).and_raise(::Redis::CannotConnectError)
end
it 'keeps project team intact upon an error' do
Sidekiq::Testing.inline! do
begin
destroy_project(project, user, {})
- rescue Redis::CannotConnectError
+ rescue ::Redis::CannotConnectError
end
end
@@ -88,10 +110,51 @@ describe Projects::DestroyService, services: true do
end
it_behaves_like 'deleting the project with pipeline and build'
- end
- context 'with execute' do
- it_behaves_like 'deleting the project with pipeline and build'
+ context 'errors' do
+ context 'when `remove_legacy_registry_tags` fails' do
+ before do
+ expect_any_instance_of(described_class)
+ .to receive(:remove_legacy_registry_tags).and_return(false)
+ end
+
+ it_behaves_like 'handles errors thrown during async destroy', "Failed to remove some tags"
+ end
+
+ context 'when `remove_repository` fails' do
+ before do
+ expect_any_instance_of(described_class)
+ .to receive(:remove_repository).and_return(false)
+ end
+
+ it_behaves_like 'handles errors thrown during async destroy', "Failed to remove project repository"
+ end
+
+ context 'when `execute` raises expected error' do
+ before do
+ expect_any_instance_of(Project)
+ .to receive(:destroy!).and_raise(StandardError.new("Other error message"))
+ end
+
+ it_behaves_like 'handles errors thrown during async destroy', "Other error message"
+ end
+
+ context 'when `execute` raises unexpected error' do
+ before do
+ expect_any_instance_of(Project)
+ .to receive(:destroy!).and_raise(Exception.new("Other error message"))
+ end
+
+ it 'allows error to bubble up and rolls back project deletion' do
+ expect do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+ end.to raise_error
+
+ expect(project.reload.pending_delete).to be(false)
+ expect(project.delete_error).to include("Other error message")
+ end
+ end
+ end
end
describe 'container registry' do
@@ -118,8 +181,7 @@ describe Projects::DestroyService, services: true do
expect_any_instance_of(ContainerRepository)
.to receive(:delete_tags!).and_return(false)
- expect{ destroy_project(project, user) }
- .to raise_error(ActiveRecord::RecordNotDestroyed)
+ expect(destroy_project(project, user)).to be false
end
end
end
@@ -144,8 +206,7 @@ describe Projects::DestroyService, services: true do
expect_any_instance_of(ContainerRepository)
.to receive(:delete_tags!).and_return(false)
- expect { destroy_project(project, user) }
- .to raise_error(Projects::DestroyService::DestroyError)
+ expect(destroy_project(project, user)).to be false
end
end
end
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index 33b267c069c..701f6cc8c6a 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::DownloadService, services: true do
+describe Projects::DownloadService do
describe 'File service' do
before do
@user = create(:user)
diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb
index 78626fbad4b..9b8c24ba112 100644
--- a/spec/services/projects/enable_deploy_key_service_spec.rb
+++ b/spec/services/projects/enable_deploy_key_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::EnableDeployKeyService, services: true do
+describe Projects::EnableDeployKeyService do
let(:deploy_key) { create(:deploy_key, public: true) }
let(:project) { create(:empty_project) }
let(:user) { project.creator}
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 0df81f3abcb..c90536ba346 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::ForkService, services: true do
+describe Projects::ForkService do
describe 'fork by user' do
before do
@from_user = create(:user)
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index e855de38037..67fe610f92a 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::ImportService, services: true do
+describe Projects::ImportService do
let!(:project) { create(:empty_project) }
let(:user) { project.creator }
diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb
index d75851134ee..8777e63a101 100644
--- a/spec/services/projects/participants_service_spec.rb
+++ b/spec/services/projects/participants_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::ParticipantsService, services: true do
+describe Projects::ParticipantsService do
describe '#groups' do
describe 'avatar_url' do
let(:project) { create(:empty_project, :public) }
@@ -13,7 +13,7 @@ describe Projects::ParticipantsService, services: true do
groups = participants.groups
expect(groups.size).to eq 1
- expect(groups.first[:avatar_url]).to eq("/uploads/system/group/avatar/#{group.id}/dk.png")
+ expect(groups.first[:avatar_url]).to eq("/uploads/-/system/group/avatar/#{group.id}/dk.png")
end
it 'should return an url for the avatar with relative url' do
@@ -24,7 +24,7 @@ describe Projects::ParticipantsService, services: true do
groups = participants.groups
expect(groups.size).to eq 1
- expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/system/group/avatar/#{group.id}/dk.png")
+ expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/-/system/group/avatar/#{group.id}/dk.png")
end
end
end
diff --git a/spec/services/projects/propagate_service_template_spec.rb b/spec/services/projects/propagate_service_template_spec.rb
index a6d43c4f0f1..2763437f184 100644
--- a/spec/services/projects/propagate_service_template_spec.rb
+++ b/spec/services/projects/propagate_service_template_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::PropagateServiceTemplate, services: true do
+describe Projects::PropagateServiceTemplate do
describe '.propagate' do
let!(:service_template) do
PushoverService.create(
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 76c52d55ae5..36db1aab557 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::TransferService, services: true do
+describe Projects::TransferService do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: user.namespace) }
@@ -30,19 +30,25 @@ describe Projects::TransferService, services: true do
transfer_project(project, user, group)
end
- it 'executes system hooks' do
- expect_any_instance_of(Projects::TransferService).to receive(:execute_system_hooks)
+ it 'expires full_path cache' do
+ expect(project).to receive(:expires_full_path_cache)
transfer_project(project, user, group)
end
+
+ it 'executes system hooks' do
+ transfer_project(project, user, group) do |service|
+ expect(service).to receive(:execute_system_hooks)
+ end
+ end
end
context 'when transfer fails' do
let!(:original_path) { project_path(project) }
- def attempt_project_transfer
+ def attempt_project_transfer(&block)
expect do
- transfer_project(project, user, group)
+ transfer_project(project, user, group, &block)
end.to raise_error(ActiveRecord::ActiveRecordError)
end
@@ -74,9 +80,9 @@ describe Projects::TransferService, services: true do
end
it "doesn't run system hooks" do
- expect_any_instance_of(Projects::TransferService).not_to receive(:execute_system_hooks)
-
- attempt_project_transfer
+ attempt_project_transfer do |service|
+ expect(service).not_to receive(:execute_system_hooks)
+ end
end
end
@@ -114,7 +120,11 @@ describe Projects::TransferService, services: true do
end
def transfer_project(project, user, new_namespace)
- Projects::TransferService.new(project, user).execute(new_namespace)
+ service = Projects::TransferService.new(project, user)
+
+ yield(service) if block_given?
+
+ service.execute(new_namespace)
end
context 'visibility level' do
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index d34652bd7ac..2ae8d5f7c54 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Projects::UnlinkForkService, services: true do
- subject { Projects::UnlinkForkService.new(fork_project, user) }
+describe Projects::UnlinkForkService do
+ subject { described_class.new(fork_project, user) }
let(:fork_link) { create(:forked_project_link) }
let(:fork_project) { fork_link.forked_to_project }
diff --git a/spec/services/projects/update_pages_configuration_service_spec.rb b/spec/services/projects/update_pages_configuration_service_spec.rb
index 8b329bc21c3..42925e73978 100644
--- a/spec/services/projects/update_pages_configuration_service_spec.rb
+++ b/spec/services/projects/update_pages_configuration_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::UpdatePagesConfigurationService, services: true do
+describe Projects::UpdatePagesConfigurationService do
let(:project) { create(:empty_project) }
subject { described_class.new(project) }
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index fc0a17296f3..aa6ad6340f5 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -96,6 +96,78 @@ describe Projects::UpdatePagesService do
expect(execute).not_to eq(:success)
end
+ describe 'maximum pages artifacts size' do
+ let(:metadata) { spy('metadata') }
+
+ before do
+ file = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip')
+ metafile = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip.meta')
+
+ build.update_attributes(artifacts_file: file)
+ build.update_attributes(artifacts_metadata: metafile)
+
+ allow(build).to receive(:artifacts_metadata_entry)
+ .and_return(metadata)
+ end
+
+ shared_examples 'pages size limit exceeded' do
+ it 'limits the maximum size of gitlab pages' do
+ subject.execute
+
+ expect(deploy_status.description)
+ .to match(/artifacts for pages are too large/)
+ end
+ end
+
+ context 'when maximum pages size is set to zero' do
+ before do
+ stub_application_setting(max_pages_size: 0)
+ end
+
+ context 'when page size does not exceed internal maximum' do
+ before do
+ allow(metadata).to receive(:total_size).and_return(200.megabytes)
+ end
+
+ it 'updates pages correctly' do
+ subject.execute
+
+ expect(deploy_status.description).not_to be_present
+ end
+ end
+
+ context 'when pages size does exceed internal maximum' do
+ before do
+ allow(metadata).to receive(:total_size).and_return(2.terabytes)
+ end
+
+ it_behaves_like 'pages size limit exceeded'
+ end
+ end
+
+ context 'when pages size is greater than max size setting' do
+ before do
+ stub_application_setting(max_pages_size: 200)
+ allow(metadata).to receive(:total_size).and_return(201.megabytes)
+ end
+
+ it_behaves_like 'pages size limit exceeded'
+ end
+
+ context 'when max size setting is greater than internal max size' do
+ before do
+ stub_application_setting(max_pages_size: 3.terabytes / 1.megabyte)
+ allow(metadata).to receive(:total_size).and_return(2.terabytes)
+ end
+
+ it_behaves_like 'pages size limit exceeded'
+ end
+ end
+
+ def deploy_status
+ GenericCommitStatus.find_by(name: 'pages:deploy')
+ end
+
def execute
subject.execute[:status]
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 05b18fef061..d7b0df9a671 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -1,11 +1,14 @@
require 'spec_helper'
-describe Projects::UpdateService, services: true do
+describe Projects::UpdateService, '#execute' do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
- let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
- describe 'update_by_user' do
+ let(:project) do
+ create(:empty_project, creator: user, namespace: user.namespace)
+ end
+
+ context 'when changing visibility level' do
context 'when visibility_level is INTERNAL' do
it 'updates the project to internal' do
result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::INTERNAL)
@@ -40,7 +43,7 @@ describe Projects::UpdateService, services: true do
it 'does not update the project to public' do
result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- expect(result).to eq({ status: :error, message: 'Visibility level unallowed' })
+ expect(result).to eq({ status: :error, message: 'New visibility level not allowed!' })
expect(project).to be_private
end
@@ -55,12 +58,13 @@ describe Projects::UpdateService, services: true do
end
end
- describe 'visibility_level' do
+ describe 'when updating project that has forks' do
let(:project) { create(:empty_project, :internal) }
let(:forked_project) { create(:forked_project_with_submodules, :internal) }
before do
- forked_project.build_forked_project_link(forked_to_project_id: forked_project.id, forked_from_project_id: project.id)
+ forked_project.build_forked_project_link(forked_to_project_id: forked_project.id,
+ forked_from_project_id: project.id)
forked_project.save
end
@@ -89,10 +93,45 @@ describe Projects::UpdateService, services: true do
end
end
- it 'returns an error result when record cannot be updated' do
- result = update_project(project, admin, { name: 'foo&bar' })
+ context 'when updating a default branch' do
+ let(:project) { create(:project, :repository) }
+
+ it 'changes a default branch' do
+ update_project(project, admin, default_branch: 'feature')
+
+ expect(Project.find(project.id).default_branch).to eq 'feature'
+ end
+ end
+
+ context 'when updating a project that contains container images' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: /image/, tags: %w[rc1])
+ create(:container_repository, project: project, name: :image)
+ end
+
+ it 'does not allow to rename the project' do
+ result = update_project(project, admin, path: 'renamed')
+
+ expect(result).to include(status: :error)
+ expect(result[:message]).to match(/contains container registry tags/)
+ end
+
+ it 'allows to update other settings' do
+ result = update_project(project, admin, public_builds: true)
+
+ expect(result[:status]).to eq :success
+ expect(project.reload.public_builds).to be true
+ end
+ end
+
+ context 'when passing invalid parameters' do
+ it 'returns an error result when record cannot be updated' do
+ result = update_project(project, admin, { name: 'foo&bar' })
- expect(result).to eq({ status: :error, message: 'Project could not be updated' })
+ expect(result).to eq({ status: :error,
+ message: 'Project could not be updated!' })
+ end
end
def update_project(project, user, opts)
diff --git a/spec/services/protected_branches/create_service_spec.rb b/spec/services/protected_branches/create_service_spec.rb
index 6ea8f309981..592f9b5929e 100644
--- a/spec/services/protected_branches/create_service_spec.rb
+++ b/spec/services/protected_branches/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedBranches::CreateService, services: true do
+describe ProtectedBranches::CreateService do
let(:project) { create(:empty_project) }
let(:user) { project.owner }
let(:params) do
diff --git a/spec/services/protected_branches/update_service_spec.rb b/spec/services/protected_branches/update_service_spec.rb
index 62bdd49a4d7..5698101af54 100644
--- a/spec/services/protected_branches/update_service_spec.rb
+++ b/spec/services/protected_branches/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedBranches::UpdateService, services: true do
+describe ProtectedBranches::UpdateService do
let(:protected_branch) { create(:protected_branch) }
let(:project) { protected_branch.project }
let(:user) { project.owner }
diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb
index d91a58e8de5..3a3cc9c1573 100644
--- a/spec/services/protected_tags/create_service_spec.rb
+++ b/spec/services/protected_tags/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedTags::CreateService, services: true do
+describe ProtectedTags::CreateService do
let(:project) { create(:empty_project) }
let(:user) { project.owner }
let(:params) do
diff --git a/spec/services/protected_tags/update_service_spec.rb b/spec/services/protected_tags/update_service_spec.rb
index e78fde4c48d..d333430088d 100644
--- a/spec/services/protected_tags/update_service_spec.rb
+++ b/spec/services/protected_tags/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedTags::UpdateService, services: true do
+describe ProtectedTags::UpdateService do
let(:protected_tag) { create(:protected_tag) }
let(:project) { protected_tag.project }
let(:user) { project.owner }
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index c9e63efbc14..92bde2c92bf 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe QuickActions::InterpretService, services: true do
+describe QuickActions::InterpretService do
let(:project) { create(:empty_project, :public) }
let(:developer) { create(:user) }
let(:developer2) { create(:user) }
@@ -9,13 +9,13 @@ describe QuickActions::InterpretService, services: true do
let(:inprogress) { create(:label, project: project, title: 'In Progress') }
let(:bug) { create(:label, project: project, title: 'Bug') }
let(:note) { build(:note, commit_id: merge_request.diff_head_sha) }
+ let(:service) { described_class.new(project, developer) }
before do
project.team << [developer, :developer]
end
describe '#execute' do
- let(:service) { described_class.new(project, developer) }
let(:merge_request) { create(:merge_request, source_project: project) }
shared_examples 'reopen command' do
@@ -261,6 +261,31 @@ describe QuickActions::InterpretService, services: true do
end
end
+ shared_examples 'duplicate command' do
+ it 'fetches issue and populates canonical_issue_id if content contains /duplicate issue_reference' do
+ issue_duplicate # populate the issue
+ _, updates = service.execute(content, issuable)
+
+ expect(updates).to eq(canonical_issue_id: issue_duplicate.id)
+ end
+ end
+
+ shared_examples 'shrug command' do
+ it 'appends ¯\_(ツ)_/¯ to the comment' do
+ new_content, _ = service.execute(content, issuable)
+
+ expect(new_content).to end_with(described_class::SHRUG)
+ end
+ end
+
+ shared_examples 'tableflip command' do
+ it 'appends (╯°□°)╯︵ ┻━┻ to the comment' do
+ new_content, _ = service.execute(content, issuable)
+
+ expect(new_content).to end_with(described_class::TABLEFLIP)
+ end
+ end
+
it_behaves_like 'reopen command' do
let(:content) { '/reopen' }
let(:issuable) { issue }
@@ -359,18 +384,18 @@ describe QuickActions::InterpretService, services: true do
let(:content) { "/assign @#{developer.username}" }
context 'Issue' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, issue)
- expect(updates).to eq(assignee_ids: [developer.id])
+ expect(updates[:assignee_ids]).to match_array([developer.id])
end
end
context 'Merge Request' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, merge_request)
- expect(updates).to eq(assignee_id: developer.id)
+ expect(updates).to eq(assignee_ids: [developer.id])
end
end
end
@@ -383,7 +408,7 @@ describe QuickActions::InterpretService, services: true do
end
context 'Issue' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, issue)
expect(updates[:assignee_ids]).to match_array([developer.id])
@@ -391,10 +416,10 @@ describe QuickActions::InterpretService, services: true do
end
context 'Merge Request' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, merge_request)
- expect(updates).to eq(assignee_id: developer.id)
+ expect(updates).to eq(assignee_ids: [developer.id])
end
end
end
@@ -422,11 +447,11 @@ describe QuickActions::InterpretService, services: true do
end
context 'Merge Request' do
- it 'populates assignee_id: nil if content contains /unassign' do
- merge_request.update(assignee_id: developer.id)
+ it 'populates assignee_ids: [] if content contains /unassign' do
+ merge_request.update(assignee_ids: [developer.id])
_, updates = service.execute(content, merge_request)
- expect(updates).to eq(assignee_id: nil)
+ expect(updates).to eq(assignee_ids: [])
end
end
end
@@ -644,6 +669,41 @@ describe QuickActions::InterpretService, services: true do
let(:issuable) { issue }
end
+ context '/duplicate command' do
+ it_behaves_like 'duplicate command' do
+ let(:issue_duplicate) { create(:issue, project: project) }
+ let(:content) { "/duplicate #{issue_duplicate.to_reference}" }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'empty command' do
+ let(:content) { '/duplicate' }
+ let(:issuable) { issue }
+ end
+
+ context 'cross project references' do
+ it_behaves_like 'duplicate command' do
+ let(:other_project) { create(:empty_project, :public) }
+ let(:issue_duplicate) { create(:issue, project: other_project) }
+ let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'empty command' do
+ let(:content) { "/duplicate imaginary#1234" }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'empty command' do
+ let(:other_project) { create(:empty_project, :private) }
+ let(:issue_duplicate) { create(:issue, project: other_project) }
+
+ let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" }
+ let(:issuable) { issue }
+ end
+ end
+ end
+
context 'when current_user cannot :admin_issue' do
let(:visitor) { create(:user) }
let(:issue) { create(:issue, project: project, author: visitor) }
@@ -693,6 +753,11 @@ describe QuickActions::InterpretService, services: true do
let(:content) { '/remove_due_date' }
let(:issuable) { issue }
end
+
+ it_behaves_like 'empty command' do
+ let(:content) { '/duplicate #{issue.to_reference}' }
+ let(:issuable) { issue }
+ end
end
context '/award command' do
@@ -726,6 +791,30 @@ describe QuickActions::InterpretService, services: true do
end
end
+ context '/shrug command' do
+ it_behaves_like 'shrug command' do
+ let(:content) { '/shrug people are people' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'shrug command' do
+ let(:content) { '/shrug' }
+ let(:issuable) { issue }
+ end
+ end
+
+ context '/tableflip command' do
+ it_behaves_like 'tableflip command' do
+ let(:content) { '/tableflip curse your sudden but enviable betrayal' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'tableflip command' do
+ let(:content) { '/tableflip' }
+ let(:issuable) { issue }
+ end
+ end
+
context '/target_branch command' do
let(:non_empty_project) { create(:project, :repository) }
let(:another_merge_request) { create(:merge_request, author: developer, source_project: non_empty_project) }
diff --git a/spec/services/repair_ldap_blocked_user_service_spec.rb b/spec/services/repair_ldap_blocked_user_service_spec.rb
index 87192457298..bf79cfe74b7 100644
--- a/spec/services/repair_ldap_blocked_user_service_spec.rb
+++ b/spec/services/repair_ldap_blocked_user_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe RepairLdapBlockedUserService, services: true do
+describe RepairLdapBlockedUserService do
let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
let(:identity) { user.ldap_identity }
- subject(:service) { RepairLdapBlockedUserService.new(user) }
+ subject(:service) { described_class.new(user) }
describe '#execute' do
it 'changes to normal block after destroying last ldap identity' do
diff --git a/spec/services/repository_archive_clean_up_service_spec.rb b/spec/services/repository_archive_clean_up_service_spec.rb
index 842585f9e54..2d7fa3f80f7 100644
--- a/spec/services/repository_archive_clean_up_service_spec.rb
+++ b/spec/services/repository_archive_clean_up_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe RepositoryArchiveCleanUpService, services: true do
+describe RepositoryArchiveCleanUpService do
describe '#execute' do
subject(:service) { described_class.new }
diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb
index cbf4f56213d..de921573b1a 100644
--- a/spec/services/search/global_service_spec.rb
+++ b/spec/services/search/global_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Search::GlobalService, services: true do
+describe Search::GlobalService do
let(:user) { create(:user) }
let(:internal_user) { create(:user) }
@@ -16,7 +16,7 @@ describe Search::GlobalService, services: true do
describe '#execute' do
context 'unauthenticated' do
it 'returns public projects only' do
- results = Search::GlobalService.new(nil, search: "searchable").execute
+ results = described_class.new(nil, search: "searchable").execute
expect(results.objects('projects')).to match_array [public_project]
end
@@ -24,19 +24,19 @@ describe Search::GlobalService, services: true do
context 'authenticated' do
it 'returns public, internal and private projects' do
- results = Search::GlobalService.new(user, search: "searchable").execute
+ results = described_class.new(user, search: "searchable").execute
expect(results.objects('projects')).to match_array [public_project, found_project, internal_project]
end
it 'returns only public & internal projects' do
- results = Search::GlobalService.new(internal_user, search: "searchable").execute
+ results = described_class.new(internal_user, search: "searchable").execute
expect(results.objects('projects')).to match_array [internal_project, public_project]
end
it 'namespace name is searchable' do
- results = Search::GlobalService.new(user, search: found_project.namespace.path).execute
+ results = described_class.new(user, search: found_project.namespace.path).execute
expect(results.objects('projects')).to match_array [found_project]
end
diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb
index 38f264f6e7b..cb3f02d2883 100644
--- a/spec/services/search/group_service_spec.rb
+++ b/spec/services/search/group_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Search::GroupService, services: true do
+describe Search::GroupService do
shared_examples_for 'group search' do
context 'finding projects by name' do
let(:user) { create(:user) }
@@ -17,7 +17,7 @@ describe Search::GroupService, services: true do
let!(:project2) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 2") }
let!(:project3) { create(:empty_project, :internal, namespace: nested_group.parent, name: "Outer #{term}") }
- let(:results) { Search::GroupService.new(user, search_group, search: term).execute }
+ let(:results) { described_class.new(user, search_group, search: term).execute }
subject { results.objects('projects') }
context 'in parent group' do
diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb
index 14f3301d9f4..69438a3fa36 100644
--- a/spec/services/search/snippet_service_spec.rb
+++ b/spec/services/search/snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Search::SnippetService, services: true do
+describe Search::SnippetService do
let(:author) { create(:author) }
let(:project) { create(:empty_project) }
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index 5cf989105d0..a6ef7561bc8 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SearchService, services: true do
+describe SearchService do
let(:user) { create(:user) }
let(:accessible_group) { create(:group, :private) }
@@ -22,7 +22,7 @@ describe SearchService, services: true do
describe '#project' do
context 'when the project is accessible' do
it 'returns the project' do
- project = SearchService.new(user, project_id: accessible_project.id).project
+ project = described_class.new(user, project_id: accessible_project.id).project
expect(project).to eq accessible_project
end
@@ -31,7 +31,7 @@ describe SearchService, services: true do
search_project = create :empty_project
search_project.add_guest(user)
- project = SearchService.new(user, project_id: search_project.id).project
+ project = described_class.new(user, project_id: search_project.id).project
expect(project).to eq search_project
end
@@ -39,7 +39,7 @@ describe SearchService, services: true do
context 'when the project is not accessible' do
it 'returns nil' do
- project = SearchService.new(user, project_id: inaccessible_project.id).project
+ project = described_class.new(user, project_id: inaccessible_project.id).project
expect(project).to be_nil
end
@@ -47,7 +47,7 @@ describe SearchService, services: true do
context 'when there is no project_id' do
it 'returns nil' do
- project = SearchService.new(user).project
+ project = described_class.new(user).project
expect(project).to be_nil
end
@@ -57,7 +57,7 @@ describe SearchService, services: true do
describe '#group' do
context 'when the group is accessible' do
it 'returns the group' do
- group = SearchService.new(user, group_id: accessible_group.id).group
+ group = described_class.new(user, group_id: accessible_group.id).group
expect(group).to eq accessible_group
end
@@ -65,7 +65,7 @@ describe SearchService, services: true do
context 'when the group is not accessible' do
it 'returns nil' do
- group = SearchService.new(user, group_id: inaccessible_group.id).group
+ group = described_class.new(user, group_id: inaccessible_group.id).group
expect(group).to be_nil
end
@@ -73,7 +73,7 @@ describe SearchService, services: true do
context 'when there is no group_id' do
it 'returns nil' do
- group = SearchService.new(user).group
+ group = described_class.new(user).group
expect(group).to be_nil
end
@@ -83,7 +83,7 @@ describe SearchService, services: true do
describe '#show_snippets?' do
context 'when :snippets is \'true\'' do
it 'returns true' do
- show_snippets = SearchService.new(user, snippets: 'true').show_snippets?
+ show_snippets = described_class.new(user, snippets: 'true').show_snippets?
expect(show_snippets).to be_truthy
end
@@ -91,7 +91,7 @@ describe SearchService, services: true do
context 'when :snippets is not \'true\'' do
it 'returns false' do
- show_snippets = SearchService.new(user, snippets: 'tru').show_snippets?
+ show_snippets = described_class.new(user, snippets: 'tru').show_snippets?
expect(show_snippets).to be_falsey
end
@@ -99,7 +99,7 @@ describe SearchService, services: true do
context 'when :snippets is missing' do
it 'returns false' do
- show_snippets = SearchService.new(user).show_snippets?
+ show_snippets = described_class.new(user).show_snippets?
expect(show_snippets).to be_falsey
end
@@ -110,7 +110,7 @@ describe SearchService, services: true do
context 'with accessible project_id' do
context 'and allowed scope' do
it 'returns the specified scope' do
- scope = SearchService.new(user, project_id: accessible_project.id, scope: 'notes').scope
+ scope = described_class.new(user, project_id: accessible_project.id, scope: 'notes').scope
expect(scope).to eq 'notes'
end
@@ -118,7 +118,7 @@ describe SearchService, services: true do
context 'and disallowed scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, project_id: accessible_project.id, scope: 'projects').scope
+ scope = described_class.new(user, project_id: accessible_project.id, scope: 'projects').scope
expect(scope).to eq 'blobs'
end
@@ -126,7 +126,7 @@ describe SearchService, services: true do
context 'and no scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, project_id: accessible_project.id).scope
+ scope = described_class.new(user, project_id: accessible_project.id).scope
expect(scope).to eq 'blobs'
end
@@ -136,7 +136,7 @@ describe SearchService, services: true do
context 'with \'true\' snippets' do
context 'and allowed scope' do
it 'returns the specified scope' do
- scope = SearchService.new(user, snippets: 'true', scope: 'snippet_titles').scope
+ scope = described_class.new(user, snippets: 'true', scope: 'snippet_titles').scope
expect(scope).to eq 'snippet_titles'
end
@@ -144,7 +144,7 @@ describe SearchService, services: true do
context 'and disallowed scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, snippets: 'true', scope: 'projects').scope
+ scope = described_class.new(user, snippets: 'true', scope: 'projects').scope
expect(scope).to eq 'snippet_blobs'
end
@@ -152,7 +152,7 @@ describe SearchService, services: true do
context 'and no scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, snippets: 'true').scope
+ scope = described_class.new(user, snippets: 'true').scope
expect(scope).to eq 'snippet_blobs'
end
@@ -162,7 +162,7 @@ describe SearchService, services: true do
context 'with no project_id, no snippets' do
context 'and allowed scope' do
it 'returns the specified scope' do
- scope = SearchService.new(user, scope: 'issues').scope
+ scope = described_class.new(user, scope: 'issues').scope
expect(scope).to eq 'issues'
end
@@ -170,7 +170,7 @@ describe SearchService, services: true do
context 'and disallowed scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, scope: 'blobs').scope
+ scope = described_class.new(user, scope: 'blobs').scope
expect(scope).to eq 'projects'
end
@@ -178,7 +178,7 @@ describe SearchService, services: true do
context 'and no scope' do
it 'returns the default scope' do
- scope = SearchService.new(user).scope
+ scope = described_class.new(user).scope
expect(scope).to eq 'projects'
end
@@ -189,7 +189,7 @@ describe SearchService, services: true do
describe '#search_results' do
context 'with accessible project_id' do
it 'returns an instance of Gitlab::ProjectSearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
project_id: accessible_project.id,
scope: 'notes',
@@ -201,7 +201,7 @@ describe SearchService, services: true do
context 'with accessible project_id and \'true\' snippets' do
it 'returns an instance of Gitlab::ProjectSearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
project_id: accessible_project.id,
snippets: 'true',
@@ -214,7 +214,7 @@ describe SearchService, services: true do
context 'with \'true\' snippets' do
it 'returns an instance of Gitlab::SnippetSearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
snippets: 'true',
search: snippet.content).search_results
@@ -225,7 +225,7 @@ describe SearchService, services: true do
context 'with no project_id and no snippets' do
it 'returns an instance of Gitlab::SearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
search: public_project.name).search_results
@@ -237,7 +237,7 @@ describe SearchService, services: true do
describe '#search_objects' do
context 'with accessible project_id' do
it 'returns objects in the project' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
project_id: accessible_project.id,
scope: 'notes',
@@ -249,7 +249,7 @@ describe SearchService, services: true do
context 'with accessible project_id and \'true\' snippets' do
it 'returns objects in the project' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
project_id: accessible_project.id,
snippets: 'true',
@@ -262,7 +262,7 @@ describe SearchService, services: true do
context 'with \'true\' snippets' do
it 'returns objects in snippets' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
snippets: 'true',
search: snippet.content).search_objects
@@ -273,7 +273,7 @@ describe SearchService, services: true do
context 'with accessible group_id' do
it 'returns objects in the group' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
group_id: accessible_group.id,
search: group_project.name).search_objects
@@ -284,7 +284,7 @@ describe SearchService, services: true do
context 'with no project_id, group_id or snippets' do
it 'returns objects in global' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
search: public_project.name).search_objects
diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb
index 5e6e43b7a90..46349c3e951 100644
--- a/spec/services/spam_service_spec.rb
+++ b/spec/services/spam_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SpamService, services: true do
+describe SpamService do
describe '#when_recaptcha_verified' do
def check_spam(issue, request, recaptcha_verified)
described_class.new(issue, request).when_recaptcha_verified(recaptcha_verified) do
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 667059f230c..b2d9862e71e 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SystemHooksService, services: true do
+describe SystemHooksService do
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:project_member) { create(:project_member) }
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 8d3dafafab2..cb59493c343 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SystemNoteService, services: true do
- include Gitlab::Routing.url_helpers
+describe SystemNoteService do
+ include Gitlab::Routing
let(:project) { create(:empty_project) }
let(:author) { create(:user) }
@@ -807,7 +807,7 @@ describe SystemNoteService, services: true do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: namespace_project_commit_url(project.namespace, project, commit),
+ url: project_commit_url(project, commit),
title: "GitLab: Mentioned on commit - #{commit.title}",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: false }
@@ -833,7 +833,7 @@ describe SystemNoteService, services: true do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: namespace_project_issue_url(project.namespace, project, issue),
+ url: project_issue_url(project, issue),
title: "GitLab: Mentioned on issue - #{issue.title}",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: false }
@@ -859,7 +859,7 @@ describe SystemNoteService, services: true do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: namespace_project_snippet_url(project.namespace, project, snippet),
+ url: project_snippet_url(project, snippet),
title: "GitLab: Mentioned on snippet - #{snippet.title}",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: false }
@@ -1098,7 +1098,57 @@ describe SystemNoteService, services: true do
diff_id = merge_request.merge_request_diff.id
line_code = change_position.line_code(project.repository)
- expect(subject.note).to include(diffs_namespace_project_merge_request_url(project.namespace, project, merge_request, diff_id: diff_id, anchor: line_code))
+ expect(subject.note).to include(diffs_project_merge_request_url(project, merge_request, diff_id: diff_id, anchor: line_code))
+ end
+ end
+
+ describe '.mark_duplicate_issue' do
+ subject { described_class.mark_duplicate_issue(noteable, project, author, canonical_issue) }
+
+ context 'within the same project' do
+ let(:canonical_issue) { create(:issue, project: project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked this issue as a duplicate of #{canonical_issue.to_reference}" }
+ end
+
+ context 'across different projects' do
+ let(:other_project) { create(:empty_project) }
+ let(:canonical_issue) { create(:issue, project: other_project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}" }
+ end
+ end
+
+ describe '.mark_canonical_issue_of_duplicate' do
+ subject { described_class.mark_canonical_issue_of_duplicate(noteable, project, author, duplicate_issue) }
+
+ context 'within the same project' do
+ let(:duplicate_issue) { create(:issue, project: project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference} as a duplicate of this issue" }
+ end
+
+ context 'across different projects' do
+ let(:other_project) { create(:empty_project) }
+ let(:duplicate_issue) { create(:issue, project: other_project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference(project)} as a duplicate of this issue" }
end
end
end
diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb
index 9f143cc5667..1b31ce29f7a 100644
--- a/spec/services/tags/create_service_spec.rb
+++ b/spec/services/tags/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Tags::CreateService, services: true do
+describe Tags::CreateService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb
index 28396fc3658..7c8c1dd0d3a 100644
--- a/spec/services/tags/destroy_service_spec.rb
+++ b/spec/services/tags/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Tags::DestroyService, services: true do
+describe Tags::DestroyService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/test_hook_service_spec.rb b/spec/services/test_hook_service_spec.rb
deleted file mode 100644
index f99fd8434c2..00000000000
--- a/spec/services/test_hook_service_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require 'spec_helper'
-
-describe TestHookService, services: true do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:hook) { create(:project_hook, project: project) }
-
- describe '#execute' do
- it "executes successfully" do
- stub_request(:post, hook.url).to_return(status: 200)
- expect(TestHookService.new.execute(hook, user)).to be_truthy
- end
- end
-end
diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb
new file mode 100644
index 00000000000..4218c15a3ce
--- /dev/null
+++ b/spec/services/test_hooks/project_service_spec.rb
@@ -0,0 +1,188 @@
+require 'spec_helper'
+
+describe TestHooks::ProjectService do
+ let(:current_user) { create(:user) }
+
+ describe '#execute' do
+ let(:project) { create(:project, :repository) }
+ let(:hook) { create(:project_hook, project: project) }
+ let(:service) { described_class.new(hook, current_user, trigger) }
+ let(:sample_data) { { data: 'sample' } }
+ let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }
+
+ context 'hook with not implemented test' do
+ let(:trigger) { 'not_implemented_events' }
+
+ it 'returns error message' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Testing not available for this hook' })
+ end
+ end
+
+ context 'push_events' do
+ let(:trigger) { 'push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:empty_repo?).and_return(true)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has at least one commit.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'tag_push_events' do
+ let(:trigger) { 'tag_push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:empty_repo?).and_return(true)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has at least one commit.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'note_events' do
+ let(:trigger) { 'note_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has notes.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:notes).and_return([Note.new])
+ allow(Gitlab::DataBuilder::Note).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'issues_events' do
+ let(:trigger) { 'issues_events' }
+ let(:issue) { build(:issue) }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has issues.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:issues).and_return([issue])
+ allow(issue).to receive(:to_hook_data).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'confidential_issues_events' do
+ let(:trigger) { 'confidential_issues_events' }
+ let(:issue) { build(:issue) }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has issues.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:issues).and_return([issue])
+ allow(issue).to receive(:to_hook_data).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'merge_requests_events' do
+ let(:trigger) { 'merge_requests_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has merge requests.' })
+ end
+
+ it 'executes hook' do
+ create(:merge_request, source_project: project)
+ allow_any_instance_of(MergeRequest).to receive(:to_hook_data).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'job_events' do
+ let(:trigger) { 'job_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has CI jobs.' })
+ end
+
+ it 'executes hook' do
+ create(:ci_build, project: project)
+ allow(Gitlab::DataBuilder::Build).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'pipeline_events' do
+ let(:trigger) { 'pipeline_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has CI pipelines.' })
+ end
+
+ it 'executes hook' do
+ create(:ci_empty_pipeline, project: project)
+ allow(Gitlab::DataBuilder::Pipeline).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'wiki_page_events' do
+ let(:trigger) { 'wiki_page_events' }
+
+ it 'returns error message if wiki disabled' do
+ allow(project).to receive(:wiki_enabled?).and_return(false)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the wiki is enabled and has pages.' })
+ end
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the wiki is enabled and has pages.' })
+ end
+
+ it 'executes hook' do
+ create(:wiki_page, wiki: project.wiki)
+ allow(Gitlab::DataBuilder::WikiPage).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+ end
+end
diff --git a/spec/services/test_hooks/system_service_spec.rb b/spec/services/test_hooks/system_service_spec.rb
new file mode 100644
index 00000000000..00d89924766
--- /dev/null
+++ b/spec/services/test_hooks/system_service_spec.rb
@@ -0,0 +1,82 @@
+require 'spec_helper'
+
+describe TestHooks::SystemService do
+ let(:current_user) { create(:user) }
+
+ describe '#execute' do
+ let(:project) { create(:project, :repository) }
+ let(:hook) { create(:system_hook) }
+ let(:service) { described_class.new(hook, current_user, trigger) }
+ let(:sample_data) { { data: 'sample' }}
+ let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }
+
+ before do
+ allow(Project).to receive(:first).and_return(project)
+ end
+
+ context 'hook with not implemented test' do
+ let(:trigger) { 'not_implemented_events' }
+
+ it 'returns error message' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Testing not available for this hook' })
+ end
+ end
+
+ context 'push_events' do
+ let(:trigger) { 'push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:empty_repo?).and_return(true)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: "Ensure project \"#{project.human_name}\" has commits." })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'tag_push_events' do
+ let(:trigger) { 'tag_push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project.repository).to receive(:tags).and_return([])
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: "Ensure project \"#{project.human_name}\" has tags." })
+ end
+
+ it 'executes hook' do
+ allow(project.repository).to receive(:tags).and_return(['tag'])
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'repository_update_events' do
+ let(:trigger) { 'repository_update_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:commit).and_return(nil)
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: "Ensure project \"#{project.human_name}\" has commits." })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Repository).to receive(:update).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+ end
+end
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 175a42a32d9..230e40de9e0 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe TodoService, services: true do
+describe TodoService do
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:non_member) { create(:user) }
@@ -873,21 +873,21 @@ describe TodoService, services: true do
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
todos = TodosFinder.new(john_doe, {}).execute
- expect { TodoService.new.mark_todos_as_done(todos, john_doe) }
+ expect { described_class.new.mark_todos_as_done(todos, john_doe) }
.to change { john_doe.todos.done.count }.from(0).to(1)
end
it 'marks an array of todos as done' do
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
- expect { TodoService.new.mark_todos_as_done([todo], john_doe) }
+ expect { described_class.new.mark_todos_as_done([todo], john_doe) }
.to change { todo.reload.state }.from('pending').to('done')
end
it 'returns the ids of updated todos' do # Needed on API
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
- expect(TodoService.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id])
+ expect(described_class.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id])
end
context 'when some of the todos are done already' do
@@ -895,23 +895,23 @@ describe TodoService, services: true do
let!(:second_todo) { create(:todo, :mentioned, user: john_doe, target: another_issue, project: project) }
it 'returns the ids of those still pending' do
- TodoService.new.mark_pending_todos_as_done(issue, john_doe)
+ described_class.new.mark_pending_todos_as_done(issue, john_doe)
- expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq([second_todo.id])
+ expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([second_todo.id])
end
it 'returns an empty array if all are done' do
- TodoService.new.mark_pending_todos_as_done(issue, john_doe)
- TodoService.new.mark_pending_todos_as_done(another_issue, john_doe)
+ described_class.new.mark_pending_todos_as_done(issue, john_doe)
+ described_class.new.mark_pending_todos_as_done(another_issue, john_doe)
- expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq([])
+ expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([])
end
end
- it 'caches the number of todos of a user', :caching do
+ it 'caches the number of todos of a user', :use_clean_rails_memory_store_caching do
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
- TodoService.new.mark_todos_as_done([todo], john_doe)
+ described_class.new.mark_todos_as_done([todo], john_doe)
expect_any_instance_of(TodosFinder).not_to receive(:execute)
diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb
index 69ed8de9c31..dc2d0e2d47a 100644
--- a/spec/services/update_release_service_spec.rb
+++ b/spec/services/update_release_service_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe UpdateReleaseService, services: true do
+describe UpdateReleaseService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:tag_name) { project.repository.tag_names.first }
let(:description) { 'Awesome release!' }
let(:new_description) { 'The best release!' }
- let(:service) { UpdateReleaseService.new(project, user) }
+ let(:service) { described_class.new(project, user) }
context 'with an existing release' do
let(:create_service) { CreateReleaseService.new(project, user) }
diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb
index 37c2e861362..ef535c5cf1f 100644
--- a/spec/services/update_snippet_service_spec.rb
+++ b/spec/services/update_snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UpdateSnippetService, services: true do
+describe UpdateSnippetService do
before do
@user = create :user
@admin = create :user, admin: true
diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb
index 95ba28dbecd..cf76a18f171 100644
--- a/spec/services/upload_service_spec.rb
+++ b/spec/services/upload_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UploadService, services: true do
+describe UploadService do
describe 'File service' do
before do
@user = create(:user)
diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb
index 2e009d4ce1c..fef4da0c76e 100644
--- a/spec/services/users/activity_service_spec.rb
+++ b/spec/services/users/activity_service_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-describe Users::ActivityService, services: true do
+describe Users::ActivityService do
include UserActivitiesHelpers
let(:user) { create(:user) }
subject(:service) { described_class.new(user, 'type') }
- describe '#execute', :redis do
+ describe '#execute', :clean_gitlab_redis_shared_state do
context 'when last activity is nil' do
before do
service.execute
diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb
index 2a6bfc1b3a0..677d4a622e1 100644
--- a/spec/services/users/build_service_spec.rb
+++ b/spec/services/users/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Users::BuildService, services: true do
+describe Users::BuildService do
describe '#execute' do
let(:params) do
{ name: 'John Doe', username: 'jduser', email: 'jd@example.com', password: 'mydummypass' }
diff --git a/spec/services/users/create_service_spec.rb b/spec/services/users/create_service_spec.rb
index 75746278573..24dac569678 100644
--- a/spec/services/users/create_service_spec.rb
+++ b/spec/services/users/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Users::CreateService, services: true do
+describe Users::CreateService do
describe '#execute' do
let(:admin_user) { create(:admin) }
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index 5409f67c091..786335120fd 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Users::DestroyService, services: true do
+describe Users::DestroyService do
describe "Deletes a user and all their personal projects" do
let!(:user) { create(:user) }
let!(:admin) { create(:admin) }
diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb
index 9e1edf1ac30..a0030ce8809 100644
--- a/spec/services/users/migrate_to_ghost_user_service_spec.rb
+++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb
@@ -1,22 +1,38 @@
require 'spec_helper'
-describe Users::MigrateToGhostUserService, services: true do
+describe Users::MigrateToGhostUserService do
let!(:user) { create(:user) }
let!(:project) { create(:project) }
let(:service) { described_class.new(user) }
context "migrating a user's associated records to the ghost user" do
context 'issues' do
- include_examples "migrating a deleted user's associated records to the ghost user", Issue do
- let(:created_record) { create(:issue, project: project, author: user) }
- let(:assigned_record) { create(:issue, project: project, assignee: user) }
+ context 'deleted user is present as both author and edited_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", Issue, [:author, :last_edited_by] do
+ let(:created_record) do
+ create(:issue, project: project, author: user, last_edited_by: user)
+ end
+ end
+ end
+
+ context 'deleted user is present only as edited_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", Issue, [:last_edited_by] do
+ let(:created_record) { create(:issue, project: project, author: create(:user), last_edited_by: user) }
+ end
end
end
context 'merge requests' do
- include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest do
- let(:created_record) { create(:merge_request, source_project: project, author: user, target_branch: "first") }
- let(:assigned_record) { create(:merge_request, source_project: project, assignee: user, target_branch: 'second') }
+ context 'deleted user is present as both author and merge_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest, [:author, :merge_user] do
+ let(:created_record) { create(:merge_request, source_project: project, author: user, merge_user: user, target_branch: "first") }
+ end
+ end
+
+ context 'deleted user is present only as both merge_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest, [:merge_user] do
+ let(:created_record) { create(:merge_request, source_project: project, merge_user: user, target_branch: "first") }
+ end
end
end
@@ -33,9 +49,8 @@ describe Users::MigrateToGhostUserService, services: true do
end
context 'award emoji' do
- include_examples "migrating a deleted user's associated records to the ghost user", AwardEmoji do
+ include_examples "migrating a deleted user's associated records to the ghost user", AwardEmoji, [:user] do
let(:created_record) { create(:award_emoji, user: user) }
- let(:author_alias) { :user }
context "when the awardable already has an award emoji of the same name assigned to the ghost user" do
let(:awardable) { create(:issue) }
diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb
index b65cadbb2f5..1c0f55d2965 100644
--- a/spec/services/users/refresh_authorized_projects_service_spec.rb
+++ b/spec/services/users/refresh_authorized_projects_service_spec.rb
@@ -8,7 +8,7 @@ describe Users::RefreshAuthorizedProjectsService do
let(:user) { project.namespace.owner }
let(:service) { described_class.new(user) }
- describe '#execute', :redis do
+ describe '#execute', :clean_gitlab_redis_shared_state do
it 'refreshes the authorizations using a lease' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain)
.and_return('foo')
diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb
new file mode 100644
index 00000000000..343804e3de0
--- /dev/null
+++ b/spec/services/users/update_service_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Users::UpdateService do
+ let(:user) { create(:user) }
+
+ describe '#execute' do
+ it 'updates the name' do
+ result = update_user(user, name: 'New Name')
+
+ expect(result).to eq(status: :success)
+ expect(user.name).to eq('New Name')
+ end
+
+ it 'returns an error result when record cannot be updated' do
+ expect do
+ update_user(user, { email: 'invalid' })
+ end.not_to change { user.reload.email }
+ end
+
+ def update_user(user, opts)
+ described_class.new(user, opts).execute
+ end
+ end
+
+ describe '#execute!' do
+ it 'updates the name' do
+ result = update_user(user, name: 'New Name')
+
+ expect(result).to be true
+ expect(user.name).to eq('New Name')
+ end
+
+ it 'raises an error when record cannot be updated' do
+ expect do
+ update_user(user, email: 'invalid')
+ end.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ def update_user(user, opts)
+ described_class.new(user, opts).execute!
+ end
+ end
+end
diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb
index b5abc46e80c..e79c12daa1c 100644
--- a/spec/services/web_hook_service_spec.rb
+++ b/spec/services/web_hook_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe WebHookService, services: true do
+describe WebHookService do
let(:project) { create(:empty_project) }
let(:project_hook) { create(:project_hook) }
let(:headers) do
@@ -12,7 +12,7 @@ describe WebHookService, services: true do
let(:data) do
{ before: 'oldrev', after: 'newrev', ref: 'ref' }
end
- let(:service_instance) { WebHookService.new(project_hook, data, 'push_hooks') }
+ let(:service_instance) { described_class.new(project_hook, data, 'push_hooks') }
describe '#execute' do
before(:each) do
@@ -53,12 +53,12 @@ describe WebHookService, services: true do
end
it 'handles exceptions' do
- exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout]
+ exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout]
exceptions.each do |exception_class|
exception = exception_class.new('Exception message')
WebMock.stub_request(:post, project_hook.url).to_raise(exception)
- expect(service_instance.execute).to eq([nil, exception.message])
+ expect(service_instance.execute).to eq({ status: :error, message: exception.message })
expect { service_instance.execute }.not_to raise_error
end
end
@@ -66,13 +66,13 @@ describe WebHookService, services: true do
it 'handles 200 status code' do
WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: 'Success')
- expect(service_instance.execute).to eq([200, 'Success'])
+ expect(service_instance.execute).to include({ status: :success, http_status: 200, message: 'Success' })
end
it 'handles 2xx status codes' do
WebMock.stub_request(:post, project_hook.url).to_return(status: 201, body: 'Success')
- expect(service_instance.execute).to eq([201, 'Success'])
+ expect(service_instance.execute).to include({ status: :success, http_status: 201, message: 'Success' })
end
context 'execution logging' do
@@ -114,7 +114,7 @@ describe WebHookService, services: true do
context 'should not log ServiceHooks' do
let(:service_hook) { create(:service_hook) }
- let(:service_instance) { WebHookService.new(service_hook, data, 'service_hook') }
+ let(:service_instance) { described_class.new(service_hook, data, 'service_hook') }
before do
WebMock.stub_request(:post, service_hook.url).to_return(status: 200, body: 'Success')
@@ -131,7 +131,7 @@ describe WebHookService, services: true do
it 'enqueue WebHookWorker' do
expect(Sidekiq::Client).to receive(:enqueue).with(WebHookWorker, project_hook.id, data, 'push_hooks')
- WebHookService.new(project_hook, data, 'push_hooks').async_execute
+ described_class.new(project_hook, data, 'push_hooks').async_execute
end
end
end
diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb
index 054e28ae7b0..fa3863e9b30 100644
--- a/spec/services/wiki_pages/create_service_spec.rb
+++ b/spec/services/wiki_pages/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe WikiPages::CreateService, services: true do
+describe WikiPages::CreateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb
index 920be4d4c8a..1668cd00ca8 100644
--- a/spec/services/wiki_pages/destroy_service_spec.rb
+++ b/spec/services/wiki_pages/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe WikiPages::DestroyService, services: true do
+describe WikiPages::DestroyService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:page) { create(:wiki_page) }
diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb
index 5e36ea4cf94..a672c84034b 100644
--- a/spec/services/wiki_pages/update_service_spec.rb
+++ b/spec/services/wiki_pages/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe WikiPages::UpdateService, services: true do
+describe WikiPages::UpdateService do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:page) { create(:wiki_page) }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index fdef6fd5221..85335643921 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -3,7 +3,6 @@ SimpleCovEnv.start!
ENV["RAILS_ENV"] ||= 'test'
ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
-# ENV['prometheus_multiproc_dir'] = 'tmp/prometheus_multiproc_dir_test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
@@ -57,8 +56,10 @@ RSpec.configure do |config|
config.include StubGitlabCalls
config.include StubGitlabData
config.include ApiHelpers, :api
- config.include Rails.application.routes.url_helpers, type: :routing
+ config.include Gitlab::Routing, type: :routing
config.include MigrationsHelpers, :migration
+ config.include StubFeatureFlags
+ config.include StubENV
config.infer_spec_type_from_file_location!
@@ -76,6 +77,13 @@ RSpec.configure do |config|
TestEnv.cleanup
end
+ config.before(:example) do
+ # Skip pre-receive hook check so we can use the web editor and merge.
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
+ # Enable all features by default for testing
+ allow(Feature).to receive(:enabled?) { true }
+ end
+
config.before(:example, :request_store) do
RequestStore.begin!
end
@@ -91,20 +99,30 @@ RSpec.configure do |config|
end
end
- config.around(:each, :caching) do |example|
+ config.around(:each, :use_clean_rails_memory_store_caching) do |example|
caching_store = Rails.cache
- Rails.cache = ActiveSupport::Cache::MemoryStore.new if example.metadata[:caching]
+ Rails.cache = ActiveSupport::Cache::MemoryStore.new
+
example.run
+
Rails.cache = caching_store
end
- config.around(:each, :redis) do |example|
- Gitlab::Redis.with(&:flushall)
+ config.around(:each, :clean_gitlab_redis_cache) do |example|
+ Gitlab::Redis::Cache.with(&:flushall)
+
+ example.run
+
+ Gitlab::Redis::Cache.with(&:flushall)
+ end
+
+ config.around(:each, :clean_gitlab_redis_shared_state) do |example|
+ Gitlab::Redis::SharedState.with(&:flushall)
Sidekiq.redis(&:flushall)
example.run
- Gitlab::Redis.with(&:flushall)
+ Gitlab::Redis::SharedState.with(&:flushall)
Sidekiq.redis(&:flushall)
end
@@ -131,3 +149,10 @@ FactoryGirl::SyntaxRunner.class_eval do
end
ActiveRecord::Migration.maintain_test_schema!
+
+Shoulda::Matchers.configure do |config|
+ config.integrate do |with|
+ with.test_framework :rspec
+ with.library :rails
+ end
+end
diff --git a/spec/requests/api/milestones_spec.rb b/spec/support/api/milestones_shared_examples.rb
index ab5ea3e8f2c..480e7d5151f 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/support/api/milestones_shared_examples.rb
@@ -1,21 +1,14 @@
-require 'spec_helper'
-
-describe API::Milestones do
- let(:user) { create(:user) }
- let!(:project) { create(:empty_project, namespace: user.namespace ) }
- let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
- let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') }
+shared_examples_for 'group and project milestones' do |route_definition|
+ let(:resource_route) { "#{route}/#{milestone.id}" }
let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
let(:label_3) { create(:label, title: 'label_3', project: project) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:another_merge_request) { create(:merge_request, :simple, source_project: project) }
- before do
- project.team << [user, :developer]
- end
-
- describe 'GET /projects/:id/milestones' do
- it 'returns project milestones' do
- get api("/projects/#{project.id}/milestones", user)
+ describe "GET #{route_definition}" do
+ it 'returns milestones list' do
+ get api(route, user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -24,13 +17,13 @@ describe API::Milestones do
end
it 'returns a 401 error if user not authenticated' do
- get api("/projects/#{project.id}/milestones")
+ get api(route)
expect(response).to have_http_status(401)
end
it 'returns an array of active milestones' do
- get api("/projects/#{project.id}/milestones?state=active", user)
+ get api("#{route}/?state=active", user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -40,7 +33,7 @@ describe API::Milestones do
end
it 'returns an array of closed milestones' do
- get api("/projects/#{project.id}/milestones?state=closed", user)
+ get api("#{route}/?state=closed", user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -50,9 +43,9 @@ describe API::Milestones do
end
it 'returns an array of milestones specified by iids' do
- other_milestone = create(:milestone, project: project)
+ other_milestone = create(:milestone, project: try(:project), group: try(:group))
- get api("/projects/#{project.id}/milestones", user), iids: [closed_milestone.iid, other_milestone.iid]
+ get api(route, user), iids: [closed_milestone.iid, other_milestone.iid]
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
@@ -61,25 +54,15 @@ describe API::Milestones do
end
it 'does not return any milestone if none found' do
- get api("/projects/#{project.id}/milestones", user), iids: [Milestone.maximum(:iid).succ]
+ get api(route, user), iids: [Milestone.maximum(:iid).succ]
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(0)
end
- end
-
- describe 'GET /projects/:id/milestones/:milestone_id' do
- it 'returns a project milestone by id' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}", user)
-
- expect(response).to have_http_status(200)
- expect(json_response['title']).to eq(milestone.title)
- expect(json_response['iid']).to eq(milestone.iid)
- end
- it 'returns a project milestone by iids array' do
- get api("/projects/#{project.id}/milestones?iids=#{closed_milestone.iid}", user)
+ it 'returns a milestone by iids array' do
+ get api("#{route}?iids=#{closed_milestone.iid}", user)
expect(response.status).to eq 200
expect(response).to include_pagination_headers
@@ -89,8 +72,8 @@ describe API::Milestones do
expect(json_response.first['id']).to eq closed_milestone.id
end
- it 'returns a project milestone by searching for title' do
- get api("/projects/#{project.id}/milestones", user), search: 'version2'
+ it 'returns a milestone by searching for title' do
+ get api(route, user), search: 'version2'
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -99,8 +82,8 @@ describe API::Milestones do
expect(json_response.first['id']).to eq milestone.id
end
- it 'returns a project milestones by searching for description' do
- get api("/projects/#{project.id}/milestones", user), search: 'open'
+ it 'returns a milestones by searching for description' do
+ get api(route, user), search: 'open'
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -110,9 +93,17 @@ describe API::Milestones do
end
end
- describe 'GET /projects/:id/milestones/:milestone_id' do
- it 'returns a project milestone by id' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}", user)
+ describe "GET #{route_definition}/:milestone_id" do
+ it 'returns a milestone by id' do
+ get api(resource_route, user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['title']).to eq(milestone.title)
+ expect(json_response['iid']).to eq(milestone.iid)
+ end
+
+ it 'returns a milestone by id' do
+ get api(resource_route, user)
expect(response).to have_http_status(200)
expect(json_response['title']).to eq(milestone.title)
@@ -120,29 +111,29 @@ describe API::Milestones do
end
it 'returns 401 error if user not authenticated' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}")
+ get api(resource_route)
expect(response).to have_http_status(401)
end
it 'returns a 404 error if milestone id not found' do
- get api("/projects/#{project.id}/milestones/1234", user)
+ get api("#{route}/1234", user)
expect(response).to have_http_status(404)
end
end
- describe 'POST /projects/:id/milestones' do
- it 'creates a new project milestone' do
- post api("/projects/#{project.id}/milestones", user), title: 'new milestone'
+ describe "POST #{route_definition}" do
+ it 'creates a new milestone' do
+ post api(route, user), title: 'new milestone'
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('new milestone')
expect(json_response['description']).to be_nil
end
- it 'creates a new project milestone with description and dates' do
- post api("/projects/#{project.id}/milestones", user),
+ it 'creates a new milestone with description and dates' do
+ post api(route, user),
title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02'
expect(response).to have_http_status(201)
@@ -152,20 +143,20 @@ describe API::Milestones do
end
it 'returns a 400 error if title is missing' do
- post api("/projects/#{project.id}/milestones", user)
+ post api(route, user)
expect(response).to have_http_status(400)
end
it 'returns a 400 error if params are invalid (duplicate title)' do
- post api("/projects/#{project.id}/milestones", user),
+ post api(route, user),
title: milestone.title, description: 'release', due_date: '2013-03-02'
expect(response).to have_http_status(400)
end
- it 'creates a new project with reserved html characters' do
- post api("/projects/#{project.id}/milestones", user), title: 'foo & bar 1.1 -> 2.2'
+ it 'creates a new milestone with reserved html characters' do
+ post api(route, user), title: 'foo & bar 1.1 -> 2.2'
expect(response).to have_http_status(201)
expect(json_response['title']).to eq('foo & bar 1.1 -> 2.2')
@@ -173,9 +164,9 @@ describe API::Milestones do
end
end
- describe 'PUT /projects/:id/milestones/:milestone_id' do
- it 'updates a project milestone' do
- put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
+ describe "PUT #{route_definition}/:milestone_id" do
+ it 'updates a milestone' do
+ put api(resource_route, user),
title: 'updated title'
expect(response).to have_http_status(200)
@@ -185,23 +176,21 @@ describe API::Milestones do
it 'removes a due date if nil is passed' do
milestone.update!(due_date: "2016-08-05")
- put api("/projects/#{project.id}/milestones/#{milestone.id}", user), due_date: nil
+ put api(resource_route, user), due_date: nil
expect(response).to have_http_status(200)
expect(json_response['due_date']).to be_nil
end
it 'returns a 404 error if milestone id not found' do
- put api("/projects/#{project.id}/milestones/1234", user),
+ put api("#{route}/1234", user),
title: 'updated title'
expect(response).to have_http_status(404)
end
- end
- describe 'PUT /projects/:id/milestones/:milestone_id to close milestone' do
- it 'updates a project milestone' do
- put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
+ it 'closes milestone' do
+ put api(resource_route, user),
state_event: 'close'
expect(response).to have_http_status(200)
@@ -209,21 +198,14 @@ describe API::Milestones do
end
end
- describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do
- it 'creates an activity event when an milestone is closed' do
- expect(Event).to receive(:create)
-
- put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
- state_event: 'close'
- end
- end
+ describe "GET #{route_definition}/:milestone_id/issues" do
+ let(:issues_route) { "#{route}/#{milestone.id}/issues" }
- describe 'GET /projects/:id/milestones/:milestone_id/issues' do
before do
milestone.issues << create(:issue, project: project)
end
- it 'returns project issues for a particular milestone' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
+ it 'returns issues for a particular milestone' do
+ get api(issues_route, user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -231,12 +213,12 @@ describe API::Milestones do
expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
- it 'returns project issues sorted by label priority' do
+ it 'returns issues sorted by label priority' do
issue_1 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_3])
issue_2 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_1])
issue_3 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_2])
- get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
+ get api(issues_route, user)
expect(json_response.first['id']).to eq(issue_2.id)
expect(json_response.second['id']).to eq(issue_3.id)
@@ -244,44 +226,58 @@ describe API::Milestones do
end
it 'matches V4 response schema for a list of issues' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user)
+ get api(issues_route, user)
expect(response).to have_http_status(200)
expect(response).to match_response_schema('public_api/v4/issues')
end
it 'returns a 401 error if user not authenticated' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}/issues")
+ get api(issues_route)
expect(response).to have_http_status(401)
end
describe 'confidential issues' do
- let(:public_project) { create(:empty_project, :public) }
- let(:milestone) { create(:milestone, project: public_project) }
- let(:issue) { create(:issue, project: public_project) }
- let(:confidential_issue) { create(:issue, confidential: true, project: public_project) }
+ let!(:public_project) { create(:empty_project, :public) }
+ let!(:context_group) { try(:group) }
+ let!(:milestone) do
+ context_group ? create(:milestone, group: context_group) : create(:milestone, project: public_project)
+ end
+ let!(:issue) { create(:issue, project: public_project) }
+ let!(:confidential_issue) { create(:issue, confidential: true, project: public_project) }
+ let!(:issues_route) do
+ if context_group
+ "#{route}/#{milestone.id}/issues"
+ else
+ "/projects/#{public_project.id}/milestones/#{milestone.id}/issues"
+ end
+ end
before do
+ # Add public project to the group in context
+ setup_for_group if context_group
+
public_project.team << [user, :developer]
milestone.issues << issue << confidential_issue
end
it 'returns confidential issues to team members' do
- get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user)
+ get api(issues_route, user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.size).to eq(2)
+ # 2 for projects, 3 for group(which has another project with an issue)
+ expect(json_response.size).to be_between(2, 3)
expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id)
end
it 'does not return confidential issues to team members with guest role' do
member = create(:user)
- project.team << [member, :guest]
+ public_project.team << [member, :guest]
- get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", member)
+ get api(issues_route, member)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -291,7 +287,7 @@ describe API::Milestones do
end
it 'does not return confidential issues to regular users' do
- get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", create(:user))
+ get api(issues_route, create(:user))
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
@@ -304,30 +300,30 @@ describe API::Milestones do
issue.labels << label_2
confidential_issue.labels << label_1
- get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user)
+ get api(issues_route, user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.size).to eq(2)
+ # 2 for projects, 3 for group(which has another project with an issue)
+ expect(json_response.size).to be_between(2, 3)
expect(json_response.first['id']).to eq(confidential_issue.id)
expect(json_response.second['id']).to eq(issue.id)
end
end
end
- describe 'GET /projects/:id/milestones/:milestone_id/merge_requests' do
- let(:merge_request) { create(:merge_request, source_project: project) }
- let(:another_merge_request) { create(:merge_request, :simple, source_project: project) }
+ describe "GET #{route_definition}/:milestone_id/merge_requests" do
+ let(:merge_requests_route) { "#{route}/#{milestone.id}/merge_requests" }
before do
milestone.merge_requests << merge_request
end
- it 'returns project merge_requests for a particular milestone' do
+ it 'returns merge_requests for a particular milestone' do
# eager-load another_merge_request
another_merge_request
- get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
+ get api(merge_requests_route, user)
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
@@ -336,12 +332,12 @@ describe API::Milestones do
expect(json_response.first['milestone']['title']).to eq(milestone.title)
end
- it 'returns project merge_requests sorted by label priority' do
+ it 'returns merge_requests sorted by label priority' do
merge_request_1 = create(:labeled_merge_request, source_branch: 'branch_1', source_project: project, milestone: milestone, labels: [label_2])
merge_request_2 = create(:labeled_merge_request, source_branch: 'branch_2', source_project: project, milestone: milestone, labels: [label_1])
merge_request_3 = create(:labeled_merge_request, source_branch: 'branch_3', source_project: project, milestone: milestone, labels: [label_3])
- get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
+ get api(merge_requests_route, user)
expect(json_response.first['id']).to eq(merge_request_2.id)
expect(json_response.second['id']).to eq(merge_request_1.id)
@@ -349,20 +345,22 @@ describe API::Milestones do
end
it 'returns a 404 error if milestone id not found' do
- get api("/projects/#{project.id}/milestones/1234/merge_requests", user)
+ not_found_route = "#{route}/1234/merge_requests"
+
+ get api(not_found_route, user)
expect(response).to have_http_status(404)
end
it 'returns a 404 if the user has no access to the milestone' do
new_user = create :user
- get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", new_user)
+ get api(merge_requests_route, new_user)
expect(response).to have_http_status(404)
end
it 'returns a 401 error if user not authenticated' do
- get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests")
+ get api(merge_requests_route)
expect(response).to have_http_status(401)
end
@@ -372,7 +370,7 @@ describe API::Milestones do
another_merge_request.labels << label_1
merge_request.labels << label_2
- get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user)
+ get api(merge_requests_route, user)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
diff --git a/spec/support/api/schema_matcher.rb b/spec/support/api/schema_matcher.rb
index e42d727672b..67599f77adb 100644
--- a/spec/support/api/schema_matcher.rb
+++ b/spec/support/api/schema_matcher.rb
@@ -1,8 +1,23 @@
+def schema_path(schema)
+ schema_directory = "#{Dir.pwd}/spec/fixtures/api/schemas"
+ "#{schema_directory}/#{schema}.json"
+end
+
RSpec::Matchers.define :match_response_schema do |schema, **options|
match do |response|
- schema_directory = "#{Dir.pwd}/spec/fixtures/api/schemas"
- schema_path = "#{schema_directory}/#{schema}.json"
+ @errors = JSON::Validator.fully_validate(schema_path(schema), response.body, options)
+
+ @errors.empty?
+ end
+
+ failure_message do |response|
+ "didn't match the schema defined by #{schema_path(schema)}" \
+ " The validation errors were:\n#{@errors.join("\n")}"
+ end
+end
- JSON::Validator.validate!(schema_path, response.body, options)
+RSpec::Matchers.define :match_schema do |schema, **options|
+ match do |data|
+ JSON::Validator.validate!(schema_path(schema), data, options)
end
end
diff --git a/spec/support/api/scopes/read_user_shared_examples.rb b/spec/support/api/scopes/read_user_shared_examples.rb
new file mode 100644
index 00000000000..3bd589d64b9
--- /dev/null
+++ b/spec/support/api/scopes/read_user_shared_examples.rb
@@ -0,0 +1,79 @@
+shared_examples_for 'allows the "read_user" scope' do
+ context 'for personal access tokens' do
+ context 'when the requesting token has the "api" scope' do
+ let(:token) { create(:personal_access_token, scopes: ['api'], user: user) }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, personal_access_token: token)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when the requesting token has the "read_user" scope' do
+ let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, personal_access_token: token)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when the requesting token does not have any required scope' do
+ let(:token) { create(:personal_access_token, scopes: ['read_registry'], user: user) }
+
+ it 'returns a "401" response' do
+ get api_call.call(path, user, personal_access_token: token)
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
+ context 'for doorkeeper (OAuth) tokens' do
+ let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
+
+ context 'when the requesting token has the "api" scope' do
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, oauth_access_token: token)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when the requesting token has the "read_user" scope' do
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "read_user" }
+
+ it 'returns a "200" response' do
+ get api_call.call(path, user, oauth_access_token: token)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when the requesting token does not have any required scope' do
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "invalid" }
+
+ it 'returns a "403" response' do
+ get api_call.call(path, user, oauth_access_token: token)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+ end
+end
+
+shared_examples_for 'does not allow the "read_user" scope' do
+ context 'when the requesting token has the "read_user" scope' do
+ let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) }
+
+ it 'returns a "401" response' do
+ post api_call.call(path, user, personal_access_token: token), attributes_for(:user, projects_limit: 3)
+
+ expect(response).to have_http_status(401)
+ end
+ end
+end
diff --git a/spec/support/api_helpers.rb b/spec/support/api_helpers.rb
index 35d1e1cfc7d..ac0aaa524b7 100644
--- a/spec/support/api_helpers.rb
+++ b/spec/support/api_helpers.rb
@@ -17,14 +17,18 @@ module ApiHelpers
# => "/api/v2/issues?foo=bar&private_token=..."
#
# Returns the relative path to the requested API resource
- def api(path, user = nil, version: API::API.version)
+ def api(path, user = nil, version: API::API.version, personal_access_token: nil, oauth_access_token: nil)
"/api/#{version}#{path}" +
# Normalize query string
(path.index('?') ? '' : '?') +
+ if personal_access_token.present?
+ "&private_token=#{personal_access_token.token}"
+ elsif oauth_access_token.present?
+ "&access_token=#{oauth_access_token.token}"
# Append private_token if given a User object
- if user.respond_to?(:private_token)
+ elsif user.respond_to?(:private_token)
"&private_token=#{user.private_token}"
else
''
@@ -32,8 +36,14 @@ module ApiHelpers
end
# Temporary helper method for simplifying V3 exclusive API specs
- def v3_api(path, user = nil)
- api(path, user, version: 'v3')
+ def v3_api(path, user = nil, personal_access_token: nil, oauth_access_token: nil)
+ api(
+ path,
+ user,
+ version: 'v3',
+ personal_access_token: personal_access_token,
+ oauth_access_token: oauth_access_token
+ )
end
def ci_api(path, user = nil)
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 4a4b037d0b1..53a90cdb26f 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -37,12 +37,20 @@ RSpec.configure do |config|
$capybara_server_already_started = true
end
- config.after(:each, :js) do
+ config.before(:example, :js) do
+ allow(Gitlab::Application.routes).to receive(:default_url_options).and_return(
+ host: Capybara.current_session.server.host,
+ port: Capybara.current_session.server.port,
+ protocol: 'http')
+ end
+
+ config.after(:example, :js) do |example|
# capybara/rspec already calls Capybara.reset_sessions! in an `after` hook,
# but `block_and_wait_for_requests_complete` is called before it so by
# calling it explicitely here, we prevent any new requests from being fired
# See https://github.com/teamcapybara/capybara/blob/ffb41cfad620de1961bb49b1562a9fa9b28c0903/lib/capybara/rspec.rb#L20-L25
- Capybara.reset_sessions!
+ # We don't reset the session when the example failed, because we need capybara-screenshot to have access to it.
+ Capybara.reset_sessions! unless example.exception
block_and_wait_for_requests_complete
end
end
diff --git a/spec/support/capybara_helpers.rb b/spec/support/capybara_helpers.rb
index b57a3493aff..3eb7bea3227 100644
--- a/spec/support/capybara_helpers.rb
+++ b/spec/support/capybara_helpers.rb
@@ -35,6 +35,11 @@ module CapybaraHelpers
visit 'about:blank'
visit url
end
+
+ # Simulate a browser restart by clearing the session cookie.
+ def clear_browser_session
+ page.driver.remove_cookie('_gitlab_session')
+ end
end
RSpec.configure do |config|
diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb
index 6e1eb5c678d..c0a5491a430 100644
--- a/spec/support/cycle_analytics_helpers.rb
+++ b/spec/support/cycle_analytics_helpers.rb
@@ -74,7 +74,9 @@ module CycleAnalyticsHelpers
def dummy_pipeline
@dummy_pipeline ||=
- Ci::Pipeline.new(sha: project.repository.commit('master').sha)
+ Ci::Pipeline.new(
+ sha: project.repository.commit('master').sha,
+ project: project)
end
def new_dummy_job(environment)
diff --git a/spec/support/devise_helpers.rb b/spec/support/devise_helpers.rb
new file mode 100644
index 00000000000..890a2d9d287
--- /dev/null
+++ b/spec/support/devise_helpers.rb
@@ -0,0 +1,14 @@
+module DeviseHelpers
+ # explicitly tells Devise which mapping to use
+ # this is needed when we are testing a Devise controller bypassing the router
+ def set_devise_mapping(context:)
+ env =
+ if context.respond_to?(:env_config)
+ context.env_config
+ elsif context.respond_to?(:env)
+ context.env
+ end
+
+ env['devise.mapping'] = Devise.mappings[:user] if env
+ end
+end
diff --git a/spec/support/dropzone_helper.rb b/spec/support/dropzone_helper.rb
index 02fdeb08afe..fe72d320fcf 100644
--- a/spec/support/dropzone_helper.rb
+++ b/spec/support/dropzone_helper.rb
@@ -54,4 +54,23 @@ module DropzoneHelper
loop until page.evaluate_script('window._dropzoneComplete === true')
end
end
+
+ def drop_in_dropzone(file_path)
+ # Generate a fake input selector
+ page.execute_script <<-JS
+ var fakeFileInput = window.$('<input/>').attr(
+ {id: 'fakeFileInput', type: 'file'}
+ ).appendTo('body');
+ JS
+
+ # Attach the file to the fake input selector with Capybara
+ attach_file('fakeFileInput', file_path)
+
+ # Add the file to a fileList array and trigger the fake drop event
+ page.execute_script <<-JS
+ var fileList = [$('#fakeFileInput')[0].files[0]];
+ var e = jQuery.Event('drop', { dataTransfer : { files : fileList } });
+ $('.dropzone')[0].dropzone.listeners[0].events.drop(e);
+ JS
+ end
end
diff --git a/spec/support/fake_migration_classes.rb b/spec/support/fake_migration_classes.rb
index 3de0460c3ca..b0fc8422857 100644
--- a/spec/support/fake_migration_classes.rb
+++ b/spec/support/fake_migration_classes.rb
@@ -1,3 +1,11 @@
class FakeRenameReservedPathMigrationV1 < ActiveRecord::Migration
include Gitlab::Database::RenameReservedPathsMigration::V1
+
+ def version
+ '20170316163845'
+ end
+
+ def name
+ "FakeRenameReservedPathMigrationV1"
+ end
end
diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb
index 50869099bb7..035428a7d9b 100644
--- a/spec/support/features/issuable_slash_commands_shared_examples.rb
+++ b/spec/support/features/issuable_slash_commands_shared_examples.rb
@@ -5,8 +5,6 @@ shared_examples 'issuable record that supports quick actions in its description
include QuickActionsHelpers
let(:master) { create(:user) }
- let(:assignee) { create(:user, username: 'bob') }
- let(:guest) { create(:user) }
let(:project) { create(:project, :public) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
let!(:label_bug) { create(:label, project: project, title: 'bug') }
@@ -15,9 +13,8 @@ shared_examples 'issuable record that supports quick actions in its description
before do
project.team << [master, :master]
- project.team << [assignee, :developer]
- project.team << [guest, :guest]
- gitlab_sign_in(master)
+
+ sign_in(master)
end
after do
@@ -28,7 +25,12 @@ shared_examples 'issuable record that supports quick actions in its description
describe "new #{issuable_type}", js: true do
context 'with commands in the description' do
it "creates the #{issuable_type} and interpret commands accordingly" do
- visit public_send("new_namespace_project_#{issuable_type}_path", project.namespace, project, new_url_opts)
+ case issuable_type
+ when :merge_request
+ visit public_send("namespace_project_new_merge_request_path", project.namespace, project, new_url_opts)
+ when :issue
+ visit public_send("new_namespace_project_issue_path", project.namespace, project, new_url_opts)
+ end
fill_in "#{issuable_type}_title", with: 'bug 345'
fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug\n/milestone %\"ASAP\""
click_button "Submit #{issuable_type}".humanize
@@ -51,6 +53,7 @@ shared_examples 'issuable record that supports quick actions in its description
context 'with a note containing commands' do
it 'creates a note without the commands and interpret the commands accordingly' do
+ assignee = create(:user, username: 'bob')
write_note("Awesome!\n/assign @bob\n/label ~bug\n/milestone %\"ASAP\"")
expect(page).to have_content 'Awesome!'
@@ -71,6 +74,7 @@ shared_examples 'issuable record that supports quick actions in its description
context 'with a note containing only commands' do
it 'does not create a note but interpret the commands accordingly' do
+ assignee = create(:user, username: 'bob')
write_note("/assign @bob\n/label ~bug\n/milestone %\"ASAP\"")
expect(page).not_to have_content '/assign @bob'
@@ -105,8 +109,12 @@ shared_examples 'issuable record that supports quick actions in its description
context "when current user cannot close #{issuable_type}" do
before do
- gitlab_sign_out
- gitlab_sign_in(guest)
+ guest = create(:user)
+ project.add_guest(guest)
+
+ sign_out(:user)
+ sign_in(guest)
+
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
end
@@ -140,8 +148,12 @@ shared_examples 'issuable record that supports quick actions in its description
context "when current user cannot reopen #{issuable_type}" do
before do
- gitlab_sign_out
- gitlab_sign_in(guest)
+ guest = create(:user)
+ project.add_guest(guest)
+
+ sign_out(:user)
+ sign_in(guest)
+
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
end
@@ -170,8 +182,11 @@ shared_examples 'issuable record that supports quick actions in its description
context "when current user cannot change title of #{issuable_type}" do
before do
- gitlab_sign_out
- gitlab_sign_in(guest)
+ guest = create(:user)
+ project.add_guest(guest)
+
+ sign_out(:user)
+ sign_in(guest)
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
end
@@ -261,6 +276,8 @@ shared_examples 'issuable record that supports quick actions in its description
describe "preview of note on #{issuable_type}" do
it 'removes quick actions from note and explains them' do
+ create(:user, username: 'bob')
+
visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable)
page.within('.js-main-target-form') do
diff --git a/spec/support/features/rss_shared_examples.rb b/spec/support/features/rss_shared_examples.rb
index 1cbb4134995..50fbbc7f55b 100644
--- a/spec/support/features/rss_shared_examples.rb
+++ b/spec/support/features/rss_shared_examples.rb
@@ -1,12 +1,12 @@
shared_examples "an autodiscoverable RSS feed with current_user's RSS token" do
it "has an RSS autodiscovery link tag with current_user's RSS token" do
- expect(page).to have_css("link[type*='atom+xml'][href*='rss_token=#{Thread.current[:current_user].rss_token}']", visible: false)
+ expect(page).to have_css("link[type*='atom+xml'][href*='rss_token=#{user.rss_token}']", visible: false)
end
end
shared_examples "it has an RSS button with current_user's RSS token" do
it "shows the RSS button with current_user's RSS token" do
- expect(page).to have_css("a:has(.fa-rss)[href*='rss_token=#{Thread.current[:current_user].rss_token}']")
+ expect(page).to have_css("a:has(.fa-rss)[href*='rss_token=#{user.rss_token}']")
end
end
diff --git a/spec/support/filter_item_select_helper.rb b/spec/support/filter_item_select_helper.rb
new file mode 100644
index 00000000000..519e84d359e
--- /dev/null
+++ b/spec/support/filter_item_select_helper.rb
@@ -0,0 +1,19 @@
+# Helper allows you to select value from filter-items
+#
+# Params
+# value - value for select
+# selector - css selector of item
+#
+# Usage:
+#
+# filter_item_select('Any Author', '.js-author-search')
+#
+module FilterItemSelectHelper
+ def filter_item_select(value, selector)
+ find(selector).click
+ wait_for_requests
+ page.within('.dropdown-content') do
+ click_link value
+ end
+ end
+end
diff --git a/spec/support/filtered_search_helpers.rb b/spec/support/filtered_search_helpers.rb
index 37cc308e613..d21c4324d9e 100644
--- a/spec/support/filtered_search_helpers.rb
+++ b/spec/support/filtered_search_helpers.rb
@@ -14,6 +14,9 @@ module FilteredSearchHelpers
filtered_search.set(search)
if submit
+ # Wait for the lazy author/assignee tokens that
+ # swap out the username with an avatar and name
+ wait_for_requests
filtered_search.send_keys(:enter)
end
end
diff --git a/spec/support/forgery_protection.rb b/spec/support/forgery_protection.rb
new file mode 100644
index 00000000000..a5e7b761651
--- /dev/null
+++ b/spec/support/forgery_protection.rb
@@ -0,0 +1,11 @@
+RSpec.configure do |config|
+ config.around(:each, :allow_forgery_protection) do |example|
+ begin
+ ActionController::Base.allow_forgery_protection = true
+
+ example.call
+ ensure
+ ActionController::Base.allow_forgery_protection = false
+ end
+ end
+end
diff --git a/spec/support/generate-seed-repo-rb b/spec/support/generate-seed-repo-rb
index 7335f74c0e9..c89389b90ca 100755
--- a/spec/support/generate-seed-repo-rb
+++ b/spec/support/generate-seed-repo-rb
@@ -15,7 +15,7 @@
require 'erb'
require 'tempfile'
-SOURCE = 'https://gitlab.com/gitlab-org/gitlab-git-test.git'.freeze
+SOURCE = File.expand_path('../gitlab-git-test.git', __FILE__).freeze
SCRIPT_NAME = 'generate-seed-repo-rb'.freeze
REPO_NAME = 'gitlab-git-test.git'.freeze
diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb
index 2bf159002a0..89fb362cf14 100644
--- a/spec/support/gitaly.rb
+++ b/spec/support/gitaly.rb
@@ -1,8 +1,6 @@
-if Gitlab::GitalyClient.enabled?
- RSpec.configure do |config|
- config.before(:each) do |example|
- next if example.metadata[:skip_gitaly_mock]
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
- end
+RSpec.configure do |config|
+ config.before(:each) do |example|
+ next if example.metadata[:skip_gitaly_mock]
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
end
end
diff --git a/spec/support/gitlab-git-test.git/HEAD b/spec/support/gitlab-git-test.git/HEAD
new file mode 100644
index 00000000000..cb089cd89a7
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/spec/support/gitlab-git-test.git/README.md b/spec/support/gitlab-git-test.git/README.md
new file mode 100644
index 00000000000..f072cd421be
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/README.md
@@ -0,0 +1,16 @@
+# Gitlab::Git test repository
+
+This repository is used by (some of) the tests in spec/lib/gitlab/git.
+
+Do not add new large files to this repository. Otherwise we needlessly
+inflate the size of the gitlab-ce repository.
+
+## How to make changes to this repository
+
+- (if needed) clone `https://gitlab.com/gitlab-org/gitlab-ce.git` to your local machine
+- clone `gitlab-ce/spec/support/gitlab-git-test.git` locally (i.e. clone from your hard drive, not from the internet)
+- make changes in your local clone of gitlab-git-test
+- run `git push` which will push to your local source `gitlab-ce/spec/support/gitlab-git-test.git`
+- in gitlab-ce: run `spec/support/prepare-gitlab-git-test-for-commit`
+- in gitlab-ce: `git add spec/support/seed_repo.rb spec/support/gitlab-git-test.git`
+- commit your changes in gitlab-ce
diff --git a/spec/support/gitlab-git-test.git/config b/spec/support/gitlab-git-test.git/config
new file mode 100644
index 00000000000..03e2d1b1e0f
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/config
@@ -0,0 +1,7 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = true
+ precomposeunicode = true
+[remote "origin"]
+ url = https://gitlab.com/gitlab-org/gitlab-git-test.git
diff --git a/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idx b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idx
new file mode 100644
index 00000000000..2253da798c4
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.idx
Binary files differ
diff --git a/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.pack b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.pack
new file mode 100644
index 00000000000..3a61107c5b1
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/objects/pack/pack-691247af2a6acb0b63b73ac0cb90540e93614043.pack
Binary files differ
diff --git a/spec/support/gitlab-git-test.git/packed-refs b/spec/support/gitlab-git-test.git/packed-refs
new file mode 100644
index 00000000000..ce5ab1f705b
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/packed-refs
@@ -0,0 +1,18 @@
+# pack-refs with: peeled fully-peeled
+0b4bc9a49b562e85de7cc9e834518ea6828729b9 refs/heads/feature
+12d65c8dd2b2676fa3ac47d955accc085a37a9c1 refs/heads/fix
+6473c90867124755509e100d0d35ebdc85a0b6ae refs/heads/fix-blob-path
+58fa1a3af4de73ea83fe25a1ef1db8e0c56f67e5 refs/heads/fix-existing-submodule-dir
+40f4a7a617393735a95a0bb67b08385bc1e7c66d refs/heads/fix-mode
+9abd6a8c113a2dd76df3fdb3d58a8cec6db75f8d refs/heads/gitattributes
+46e1395e609395de004cacd4b142865ab0e52a29 refs/heads/gitattributes-updated
+4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6 refs/heads/master
+5937ac0a7beb003549fc5fd26fc247adbce4a52e refs/heads/merge-test
+f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8 refs/tags/v1.0.0
+^6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b refs/tags/v1.1.0
+^5937ac0a7beb003549fc5fd26fc247adbce4a52e
+10d64eed7760f2811ee2d64b44f1f7d3b364f17b refs/tags/v1.2.0
+^eb49186cfa5c4338011f5f590fac11bd66c5c631
+2ac1f24e253e08135507d0830508febaaccf02ee refs/tags/v1.2.1
+^fa1b1e6c004a68b7d8763b86455da9e6b23e36d6
diff --git a/spec/support/gitlab-git-test.git/refs/heads/.gitkeep b/spec/support/gitlab-git-test.git/refs/heads/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/refs/heads/.gitkeep
diff --git a/spec/support/gitlab-git-test.git/refs/tags/.gitkeep b/spec/support/gitlab-git-test.git/refs/tags/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/spec/support/gitlab-git-test.git/refs/tags/.gitkeep
diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb
new file mode 100644
index 00000000000..96ea6f28b30
--- /dev/null
+++ b/spec/support/gpg_helpers.rb
@@ -0,0 +1,202 @@
+module GpgHelpers
+ module User1
+ extend self
+
+ def signed_commit_signature
+ <<~SIGNATURE
+ -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1
+
+ iJwEAAECAAYFAliu264ACgkQzPvhnwCsix1VXgP9F6zwAMb3OXKZzqGxJ4MQIBoL
+ OdiUSJpL/4sIA9uhFeIv3GIA+uhsG1BHHsG627+sDy7b8W9VWEd7tbcoz4Mvhf3P
+ 8g0AIt9/KJuStQZDrXwP1uP6Rrl759nDcNpoOKdSQ5EZ1zlRzeDROlZeDp7Ckfvw
+ GLmN/74Gl3pk0wfgHFY=
+ =wSgS
+ -----END PGP SIGNATURE-----
+ SIGNATURE
+ end
+
+ def signed_commit_base_data
+ <<~SIGNEDDATA
+ tree ed60cfd202644fda1abaf684e7d965052db18c13
+ parent caf6a0334a855e12f30205fff3d7333df1f65127
+ author Nannie Bernhard <nannie.bernhard@example.com> 1487854510 +0100
+ committer Nannie Bernhard <nannie.bernhard@example.com> 1487854510 +0100
+
+ signed commit, verified key/email
+ SIGNEDDATA
+ end
+
+ def secret_key
+ <<~KEY.strip
+ -----BEGIN PGP PRIVATE KEY BLOCK-----
+ Version: GnuPG v1
+
+ lQHYBFiu1ScBBADUhWsrlWHp5e7ASlI5iMcA0XN43fivhVlGYJJy4Ii3Hr2i4f5s
+ VffHS8QyhgxxzSnPwe2OKnZWWL9cHzUFbiG3fHalEBTjpB+7pG4HBgU8R/tiDOu8
+ vkAR+tfJbkuRs9XeG3dGKBX/8WRhIfRucYnM+04l2Myyo5zIx7thJmxXjwARAQAB
+ AAP/XUtcqrtfSnDYCK4Xvo4e3msUSAEZxOPDNzP51lhfbBQgp7qSGDj9Fw5ZyNwz
+ 5llse3nksT5OyMUY7HX+rq2UOs12a/piLqvhtX1okp/oTAETmKXNYkZLenv6t94P
+ NqLi0o2AnXAvL9ueXa7WUY3l4DkvuLcjT4+9Ut2Y71zIjeECAN7q9ohNL7E8tNkf
+ Elsbx+8KfyHRQXiSUYaQLlvDRq2lYCKIS7sogTqjZMEgbZx2mRX1fakRlvcmqOwB
+ QoX34zcCAPQPd+yTteNUV12uvDaj8V9DICktPPhbHdYYaUoHjF8RrIHCTRUPzk9E
+ KzCL9dUP8eXPPBV/ty+zjUwl69IgCmkB/3pnNZ0D4EJsNgu24UgI0N+c8H/PE1D6
+ K+bGQ/jK83uYPMXJUsiojssCHLGNp7eBGHFn1PpEqZphgVI50ZMrZQWhJbQtTmFu
+ bmllIEJlcm5oYXJkIDxuYW5uaWUuYmVybmhhcmRAZXhhbXBsZS5jb20+iLgEEwEC
+ ACIFAliu1ScCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMz74Z8ArIsd
+ p5ID/32hRalvTY+V+QAtzHlGdxugweSBzNgRT3A4UiC9chF6zBOEIw689lqmK6L4
+ i3Il9XeKMl87wi9tsVy9TuOMYDTvcFvu1vMAQ5AsDXqZaAEtCUZpFZscNbi7AXG+
+ QkoDQbMSxp0Rd6eIRJpk9zis5co87f78xJBZLZua+8awFMS6nQHYBFiu1ScBBADI
+ XkITf+kKCkD+n8tMsdTLInefu8KrJ8p7YRYCCabEXnWRsDb5zxUAG2VXCVUhYl6Q
+ XQybkNiBaduS+uxilz7gtYZUMFJvQ09+fV7D2N9B7u/1bGdIYz+cDFJnEJitLY4w
+ /nju2Sno5CL5Ead8sZuslKetSXPYHR/kbW462EOw5wARAQABAAP+IoZfU1XUdVbr
+ +RPWp3ny5SekviDPu8co9BZ4ANTh5+8wyfA3oNbGUxTlYthoU07MZYqq+/k63R28
+ 6HgVGC3gdvCiRMGmryIQ6roLLRXkfzjXrI7Lgnhx4OtVjo62pAKDqdl45wEa1Q+M
+ v08CQF6XNpb5R9Xszz4aBC4eV0KjtjkCANlGSQHZ1B81g+iltj1FAhRHkyUFlrc1
+ cqLVhNgxtHZ96+R57Uk2A7dIJBsE00eIYaHOfk5X5GD/95s1QvPcQskCAOwUk5xj
+ NeQ6VV/1+cI91TrWU6VnT2Yj8632fM/JlKKfaS15pp8t5Ha6pNFr3xD4KgQutchq
+ fPsEOjaU7nwQ/i8B/1rDPTYfNXFpRNt33WAB1XtpgOIHlpmOfaYYqf6lneTlZWBc
+ TgyO+j+ZsHAvP18ugIRkU8D192NflzgAGwXLryijyYifBBgBAgAJBQJYrtUnAhsM
+ AAoJEMz74Z8ArIsdlkUEALTl6QUutJsqwVF4ZXKmmw0IEk8PkqW4G+tYRDHJMs6Z
+ O0nzDS89BG2DL4/UlOs5wRvERnlJYz01TMTxq/ciKaBTEjygFIv9CgIEZh97VacZ
+ TIqcF40k9SbpJNnh3JLf94xsNxNRJTEhbVC3uruaeILue/IR7pBMEyCs49Gcguwy
+ =b6UD
+ -----END PGP PRIVATE KEY BLOCK-----
+ KEY
+ end
+
+ def public_key
+ <<~KEY.strip
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
+ Version: GnuPG v1
+
+ mI0EWK7VJwEEANSFayuVYenl7sBKUjmIxwDRc3jd+K+FWUZgknLgiLcevaLh/mxV
+ 98dLxDKGDHHNKc/B7Y4qdlZYv1wfNQVuIbd8dqUQFOOkH7ukbgcGBTxH+2IM67y+
+ QBH618luS5Gz1d4bd0YoFf/xZGEh9G5xicz7TiXYzLKjnMjHu2EmbFePABEBAAG0
+ LU5hbm5pZSBCZXJuaGFyZCA8bmFubmllLmJlcm5oYXJkQGV4YW1wbGUuY29tPoi4
+ BBMBAgAiBQJYrtUnAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDM++Gf
+ AKyLHaeSA/99oUWpb02PlfkALcx5RncboMHkgczYEU9wOFIgvXIReswThCMOvPZa
+ piui+ItyJfV3ijJfO8IvbbFcvU7jjGA073Bb7tbzAEOQLA16mWgBLQlGaRWbHDW4
+ uwFxvkJKA0GzEsadEXeniESaZPc4rOXKPO3+/MSQWS2bmvvGsBTEuriNBFiu1ScB
+ BADIXkITf+kKCkD+n8tMsdTLInefu8KrJ8p7YRYCCabEXnWRsDb5zxUAG2VXCVUh
+ Yl6QXQybkNiBaduS+uxilz7gtYZUMFJvQ09+fV7D2N9B7u/1bGdIYz+cDFJnEJit
+ LY4w/nju2Sno5CL5Ead8sZuslKetSXPYHR/kbW462EOw5wARAQABiJ8EGAECAAkF
+ Aliu1ScCGwwACgkQzPvhnwCsix2WRQQAtOXpBS60myrBUXhlcqabDQgSTw+Spbgb
+ 61hEMckyzpk7SfMNLz0EbYMvj9SU6znBG8RGeUljPTVMxPGr9yIpoFMSPKAUi/0K
+ AgRmH3tVpxlMipwXjST1Jukk2eHckt/3jGw3E1ElMSFtULe6u5p4gu578hHukEwT
+ IKzj0ZyC7DI=
+ =Ug0r
+ -----END PGP PUBLIC KEY BLOCK-----
+ KEY
+ end
+
+ def primary_keyid
+ fingerprint[-16..-1]
+ end
+
+ def fingerprint
+ '5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D'
+ end
+
+ def names
+ ['Nannie Bernhard']
+ end
+
+ def emails
+ ['nannie.bernhard@example.com']
+ end
+ end
+
+ module User2
+ extend self
+
+ def private_key
+ <<~KEY.strip
+ -----BEGIN PGP PRIVATE KEY BLOCK-----
+ Version: GnuPG v1
+
+ lQHYBFiuqioBBADg46jkiATWMy9t1npxFWJ77xibPXdUo36LAZgZ6uGungSzcFL4
+ 50bdEyMMGm5RJp6DCYkZlwQDlM//YEqwf0Cmq/AibC5m9bHr7hf5sMxl40ssJ4fj
+ dzT6odihO0vxD2ARSrtiwkESzFxjJ51mjOfdPvAGf0ucxzgeRfUlCrM3kwARAQAB
+ AAP8CJlDFnbywR9dWfqBxi19sFMOk/smCObNQanuTcx6CDcu4zHi0Yxx6BoNCQES
+ cDRCLX5HevnpZngzQB3qa7dga+yqxKzwO8v0P0hliL81B1ZVXUk9TWhBj3NS3m3v
+ +kf2XeTxuZFb9fj44/4HpfbQ2yazTs/Xa+/ZeMqFPCYSNEECAOtjIbwHdfjkpVWR
+ uiwphRkNimv5hdObufs63m9uqhpKPdPKmr2IXgahPZg5PooxqE0k9IXaX2pBsJUF
+ DyuL1dsCAPSVL+YAOviP8ecM1jvdKpkFDd67kR5C+7jEvOGl+c2aX3qLvKt62HPR
+ +DxvYE0Oy0xfoHT14zNSfqthmlhIPqkB/i4WyJaafQVvkkoA9+A5aXbyihOR+RTx
+ p+CMNYvaAplFAyey7nv8l5+la/N+Sv86utjaenLZmCf34nDQEZy7rFWny7QvQmV0
+ dGUgQ2FydHdyaWdodCA8YmV0dGUuY2FydHdyaWdodEBleGFtcGxlLmNvbT6IuAQT
+ AQIAIgUCWK6qKgIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQv52SX5Ee
+ /WVCGwP/QsOLTTyEJ6hl0Yy7DLY3kUxS6xiD9fW1FDoTQlxhiO+8TmghmhdtU3TI
+ ssP30/Su3pNKW3TkILtE9U8I2krEpsX5NkyMwmI6LXdeZjli2Lvtkx0Fm0Psd4HO
+ ORYJW5HqTx4jDLzeeIcYjqnobztDpfG8ONDvB0EI0GnCTOZNggG0L0JldHRlIENh
+ cnR3cmlnaHQgPGJldHRlLmNhcnR3cmlnaHRAZXhhbXBsZS5uZXQ+iLgEEwECACIF
+ AlivAsUCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEL+dkl+RHv1lXOwE
+ ANh7ce/vUjv6VMkO8o5OZXszhKE5+MSmYO8v/kkHcXNccC5wI6VF4K//r41p8Cyk
+ 9NzW7Kzjt2+14/BBqWugCx3xjWCuf88KH5PHbuSmfVYbzJmNSy6rfPmusZG5ePqD
+ xp5l2qQxMdRUX0Z36D/koM4N0ls6PAf6Xrdv9s6IBMMVnQHYBFiuqioBBADe5nUd
+ VOcbZlnxOjl0KBAT+A5bmyBLUT0BmLPsmA4PuXDSth7WvibPC8wcCdCYVk0IRMYn
+ eZUiWq/o5c4rthfLR4jg8kruvomQ4E4d4hyI6R0MLxXYZ3XMu67VuScFgbLURw1e
+ RZ16ANd3Nc1VuFW7ms0vCG0idB8iSZBoULaK8QARAQABAAP5AdCfUT/y2kmi75iF
+ ZX1ahSkax9LraEWW8TOCuolR6v2b7jFKrr2xX/P1A2DulID2Y1v4/5MJPHR/1G4D
+ l95Fkw+iGsTvKB5rPG5xye0vOYbbujRa6B9LL6s4Taf486shEegOrdjN9FIweM6f
+ vuVaDYzIk8Qwv5/sStEBxx8rxIkCAOBftFi56AY0gLniyEMAvVRjyVeOZPPJbS8i
+ v6L9asJB5wdsGJxJVyUZ/ylar5aCS7sroOcYTN2b1tOPoWuGqIkCAP5RlDRgm3Zg
+ xL6hXejqZp3G1/DXhKBSI/yUTR/D89H5/qNQe3W7dZqns9mSAJNtqOu+UMZ5UreY
+ Ond0/dmL5SkCAOO5r6gXM8ZDcNjydlQexCLnH70yVkCL6hG9Va1gOuFyUztRnCd+
+ E35YRCEwZREZDr87BRr2Aak5t+lb1EFVqV+nvYifBBgBAgAJBQJYrqoqAhsMAAoJ
+ EL+dkl+RHv1lQggEANWwQwrlT2BFLWV8Fx+wlg31+mcjkTq0LaWu3oueAluoSl93
+ 2B6ToruMh66JoxpSDU44x3JbCaZ/6poiYs5Aff8ZeyEVlfkVaQ7IWd5spjpXaS4i
+ oCOfkZepmbTuE7TPQWM4iBAtuIfiJGiwcpWWM+KIH281yhfCcbRzzFLsCVQx
+ =yEqv
+ -----END PGP PRIVATE KEY BLOCK-----
+ KEY
+ end
+
+ def public_key
+ <<~KEY.strip
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
+ Version: GnuPG v1
+
+ mI0EWK6qKgEEAODjqOSIBNYzL23WenEVYnvvGJs9d1SjfosBmBnq4a6eBLNwUvjn
+ Rt0TIwwablEmnoMJiRmXBAOUz/9gSrB/QKar8CJsLmb1sevuF/mwzGXjSywnh+N3
+ NPqh2KE7S/EPYBFKu2LCQRLMXGMnnWaM590+8AZ/S5zHOB5F9SUKszeTABEBAAG0
+ L0JldHRlIENhcnR3cmlnaHQgPGJldHRlLmNhcnR3cmlnaHRAZXhhbXBsZS5jb20+
+ iLgEEwECACIFAliuqioCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEL+d
+ kl+RHv1lQhsD/0LDi008hCeoZdGMuwy2N5FMUusYg/X1tRQ6E0JcYYjvvE5oIZoX
+ bVN0yLLD99P0rt6TSlt05CC7RPVPCNpKxKbF+TZMjMJiOi13XmY5Yti77ZMdBZtD
+ 7HeBzjkWCVuR6k8eIwy83niHGI6p6G87Q6XxvDjQ7wdBCNBpwkzmTYIBtC9CZXR0
+ ZSBDYXJ0d3JpZ2h0IDxiZXR0ZS5jYXJ0d3JpZ2h0QGV4YW1wbGUubmV0Poi4BBMB
+ AgAiBQJYrwLFAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRC/nZJfkR79
+ ZVzsBADYe3Hv71I7+lTJDvKOTmV7M4ShOfjEpmDvL/5JB3FzXHAucCOlReCv/6+N
+ afAspPTc1uys47dvtePwQalroAsd8Y1grn/PCh+Tx27kpn1WG8yZjUsuq3z5rrGR
+ uXj6g8aeZdqkMTHUVF9Gd+g/5KDODdJbOjwH+l63b/bOiATDFbiNBFiuqioBBADe
+ 5nUdVOcbZlnxOjl0KBAT+A5bmyBLUT0BmLPsmA4PuXDSth7WvibPC8wcCdCYVk0I
+ RMYneZUiWq/o5c4rthfLR4jg8kruvomQ4E4d4hyI6R0MLxXYZ3XMu67VuScFgbLU
+ Rw1eRZ16ANd3Nc1VuFW7ms0vCG0idB8iSZBoULaK8QARAQABiJ8EGAECAAkFAliu
+ qioCGwwACgkQv52SX5Ee/WVCCAQA1bBDCuVPYEUtZXwXH7CWDfX6ZyOROrQtpa7e
+ i54CW6hKX3fYHpOiu4yHromjGlINTjjHclsJpn/qmiJizkB9/xl7IRWV+RVpDshZ
+ 3mymOldpLiKgI5+Rl6mZtO4TtM9BYziIEC24h+IkaLBylZYz4ogfbzXKF8JxtHPM
+ UuwJVDE=
+ =0vYo
+ -----END PGP PUBLIC KEY BLOCK-----
+ KEY
+ end
+
+ def primary_keyid
+ fingerprint[-16..-1]
+ end
+
+ def fingerprint
+ '6D494CA6FC90C0CAE0910E42BF9D925F911EFD65'
+ end
+
+ def names
+ ['Bette Cartwright', 'Bette Cartwright']
+ end
+
+ def emails
+ ['bette.cartwright@example.com', 'bette.cartwright@example.net']
+ end
+ end
+end
diff --git a/spec/support/issuable_shared_examples.rb b/spec/support/issuable_shared_examples.rb
index 03011535351..970fe10db2b 100644
--- a/spec/support/issuable_shared_examples.rb
+++ b/spec/support/issuable_shared_examples.rb
@@ -5,3 +5,34 @@ shared_examples 'cache counters invalidator' do
described_class.new(project, user, {}).execute(merge_request)
end
end
+
+shared_examples 'system notes for milestones' do
+ def update_issuable(opts)
+ issuable = try(:issue) || try(:merge_request)
+ described_class.new(project, user, opts).execute(issuable)
+ end
+
+ context 'group milestones' do
+ let(:group) { create(:group) }
+ let(:group_milestone) { create(:milestone, group: group) }
+
+ before do
+ project.update(namespace: group)
+ create(:group_member, group: group, user: user)
+ end
+
+ it 'does not create system note' do
+ expect do
+ update_issuable(milestone: group_milestone)
+ end.not_to change { Note.system.count }
+ end
+ end
+
+ context 'project milestones' do
+ it 'creates system note' do
+ expect do
+ update_issuable(milestone: create(:milestone))
+ end.to change { Note.system.count }.by(1)
+ end
+ end
+end
diff --git a/spec/support/issue_helpers.rb b/spec/support/issue_helpers.rb
index 85241793743..ffd72515f37 100644
--- a/spec/support/issue_helpers.rb
+++ b/spec/support/issue_helpers.rb
@@ -1,6 +1,6 @@
module IssueHelpers
def visit_issues(project, opts = {})
- visit namespace_project_issues_path project.namespace, project, opts
+ visit project_issues_path project, opts
end
def first_issue
diff --git a/spec/support/issue_tracker_service_shared_example.rb b/spec/support/issue_tracker_service_shared_example.rb
index e70b3963d9d..a6ab03cb808 100644
--- a/spec/support/issue_tracker_service_shared_example.rb
+++ b/spec/support/issue_tracker_service_shared_example.rb
@@ -8,15 +8,15 @@ end
RSpec.shared_examples 'allows project key on reference pattern' do |url_attr|
it 'allows underscores in the project name' do
- expect(subject.reference_pattern.match('EXT_EXT-1234')[0]).to eq 'EXT_EXT-1234'
+ expect(described_class.reference_pattern.match('EXT_EXT-1234')[0]).to eq 'EXT_EXT-1234'
end
it 'allows numbers in the project name' do
- expect(subject.reference_pattern.match('EXT3_EXT-1234')[0]).to eq 'EXT3_EXT-1234'
+ expect(described_class.reference_pattern.match('EXT3_EXT-1234')[0]).to eq 'EXT3_EXT-1234'
end
it 'requires the project name to begin with A-Z' do
- expect(subject.reference_pattern.match('3EXT_EXT-1234')).to eq nil
- expect(subject.reference_pattern.match('EXT_EXT-1234')[0]).to eq 'EXT_EXT-1234'
+ expect(described_class.reference_pattern.match('3EXT_EXT-1234')).to eq nil
+ expect(described_class.reference_pattern.match('EXT_EXT-1234')[0]).to eq 'EXT_EXT-1234'
end
end
diff --git a/spec/support/jira_service_helper.rb b/spec/support/jira_service_helper.rb
index 97ae0b6afc5..0b5f66597fd 100644
--- a/spec/support/jira_service_helper.rb
+++ b/spec/support/jira_service_helper.rb
@@ -51,7 +51,7 @@ module JiraServiceHelper
end
def jira_project_url
- JIRA_API + "/project/#{jira_tracker.project_key}"
+ JIRA_API + "/project"
end
def jira_api_comment_url(issue_id)
diff --git a/spec/support/json_response_helpers.rb b/spec/support/json_response_helpers.rb
index e8d2ef2d7f0..aa235529c56 100644
--- a/spec/support/json_response_helpers.rb
+++ b/spec/support/json_response_helpers.rb
@@ -3,7 +3,7 @@ shared_context 'JSON response' do
end
RSpec.configure do |config|
- config.include_context 'JSON response', type: :controller
+ config.include_context 'JSON response'
config.include_context 'JSON response', type: :request
config.include_context 'JSON response', :api
end
diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb
index 879386b5437..c714d1b08a6 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -1,4 +1,6 @@
module LoginHelpers
+ include DeviseHelpers
+
# Internal: Log in as a specific user or a new user of a specific role
#
# user_or_role - User object, or a role to create (e.g., :admin, :user)
@@ -15,14 +17,16 @@ module LoginHelpers
# user = create(:user)
# gitlab_sign_in(user)
def gitlab_sign_in(user_or_role, **kwargs)
- @user =
+ user =
if user_or_role.is_a?(User)
user_or_role
else
create(user_or_role)
end
- gitlab_sign_in_with(@user, **kwargs)
+ gitlab_sign_in_with(user, **kwargs)
+
+ user
end
def gitlab_sign_in_via(provider, user, uid)
@@ -35,13 +39,8 @@ module LoginHelpers
def gitlab_sign_out
find(".header-user-dropdown-toggle").click
click_link "Sign out"
- # check the sign_in button
- expect(page).to have_button('Sign in')
- end
- # Logout without JavaScript driver
- def gitlab_sign_out_direct
- page.driver.submit :delete, '/users/sign_out', {}
+ expect(page).to have_button('Sign in')
end
private
@@ -58,8 +57,16 @@ module LoginHelpers
check 'user_remember_me' if remember
click_button "Sign in"
+ end
- Thread.current[:current_user] = user
+ def login_via(provider, user, uid, remember_me: false)
+ mock_auth_hash(provider, uid, user.email)
+ visit new_user_session_path
+ expect(page).to have_content('Sign in with')
+
+ check 'remember_me' if remember_me
+
+ click_link "oauth-login-#{provider}"
end
def mock_auth_hash(provider, uid, email)
@@ -89,4 +96,26 @@ module LoginHelpers
})
Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[:saml]
end
+
+ def mock_saml_config
+ OpenStruct.new(name: 'saml', label: 'saml', args: {
+ assertion_consumer_service_url: 'https://localhost:3443/users/auth/saml/callback',
+ idp_cert_fingerprint: '26:43:2C:47:AF:F0:6B:D0:07:9C:AD:A3:74:FE:5D:94:5F:4E:9E:52',
+ idp_sso_target_url: 'https://idp.example.com/sso/saml',
+ issuer: 'https://localhost:3443/',
+ name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
+ })
+ end
+
+ def stub_omniauth_saml_config(messages)
+ set_devise_mapping(context: Rails.application)
+ Rails.application.routes.disable_clear_and_finalize = true
+ Rails.application.routes.draw do
+ post '/users/auth/saml' => 'omniauth_callbacks#saml'
+ end
+ allow(Gitlab::OAuth::Provider).to receive_messages(providers: [:saml], config_for: mock_saml_config)
+ stub_omniauth_setting(messages)
+ allow_any_instance_of(Object).to receive(:user_saml_omniauth_authorize_path).and_return('/users/auth/saml')
+ allow_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml')
+ end
end
diff --git a/spec/support/malicious_regexp_shared_examples.rb b/spec/support/malicious_regexp_shared_examples.rb
new file mode 100644
index 00000000000..ac5d22298bb
--- /dev/null
+++ b/spec/support/malicious_regexp_shared_examples.rb
@@ -0,0 +1,8 @@
+shared_examples 'malicious regexp' do
+ let(:malicious_text) { 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!' }
+ let(:malicious_regexp) { '(?i)^(([a-z])+.)+[A-Z]([a-z])+$' }
+
+ it 'takes under a second' do
+ expect { Timeout.timeout(1) { subject } }.not_to raise_error
+ end
+end
diff --git a/spec/support/matchers/access_matchers_for_controller.rb b/spec/support/matchers/access_matchers_for_controller.rb
new file mode 100644
index 00000000000..ff60bd0c0ae
--- /dev/null
+++ b/spec/support/matchers/access_matchers_for_controller.rb
@@ -0,0 +1,108 @@
+# AccessMatchersForController
+#
+# For testing authorize_xxx in controller.
+module AccessMatchersForController
+ extend RSpec::Matchers::DSL
+ include Warden::Test::Helpers
+
+ EXPECTED_STATUS_CODE_ALLOWED = [200, 201, 302].freeze
+ EXPECTED_STATUS_CODE_DENIED = [401, 404].freeze
+
+ def emulate_user(role, membership = nil)
+ case role
+ when :admin
+ user = create(:admin)
+ sign_in(user)
+ when :user
+ user = create(:user)
+ sign_in(user)
+ when :external
+ user = create(:user, external: true)
+ sign_in(user)
+ when :visitor
+ user = nil
+ when User
+ user = role
+ sign_in(user)
+ when *Gitlab::Access.sym_options_with_owner.keys # owner, master, developer, reporter, guest
+ raise ArgumentError, "cannot emulate #{role} without membership parent" unless membership
+
+ user = create_user_by_membership(role, membership)
+ sign_in(user)
+ else
+ raise ArgumentError, "cannot emulate user #{role}"
+ end
+
+ user
+ end
+
+ def create_user_by_membership(role, membership)
+ if role == :owner && membership.owner
+ user = membership.owner
+ else
+ user = create(:user)
+ membership.public_send(:"add_#{role}", user)
+ end
+ user
+ end
+
+ def description_for(role, type, expected, result)
+ "be #{type} for #{role}. Expected: #{expected.join(',')} Got: #{result}"
+ end
+
+ def update_owner(objects, user)
+ return unless objects
+
+ objects.each do |object|
+ if object.respond_to?(:owner)
+ object.update_attribute(:owner, user)
+ elsif object.respond_to?(:user)
+ object.update_attribute(:user, user)
+ else
+ raise ArgumentError, "cannot own this object #{object}"
+ end
+ end
+ end
+
+ matcher :be_allowed_for do |role|
+ match do |action|
+ user = emulate_user(role, @membership)
+ update_owner(@objects, user)
+ action.call
+
+ EXPECTED_STATUS_CODE_ALLOWED.include?(response.status)
+ end
+
+ chain :of do |membership|
+ @membership = membership
+ end
+
+ chain :own do |*objects|
+ @objects = objects
+ end
+
+ description { description_for(role, 'allowed', EXPECTED_STATUS_CODE_ALLOWED, response.status) }
+ supports_block_expectations
+ end
+
+ matcher :be_denied_for do |role|
+ match do |action|
+ user = emulate_user(role, @membership)
+ update_owner(@objects, user)
+ action.call
+
+ EXPECTED_STATUS_CODE_DENIED.include?(response.status)
+ end
+
+ chain :of do |membership|
+ @membership = membership
+ end
+
+ chain :own do |*objects|
+ @objects = objects
+ end
+
+ description { description_for(role, 'denied', EXPECTED_STATUS_CODE_DENIED, response.status) }
+ supports_block_expectations
+ end
+end
diff --git a/spec/support/matchers/be_utf8.rb b/spec/support/matchers/be_utf8.rb
new file mode 100644
index 00000000000..ea806352422
--- /dev/null
+++ b/spec/support/matchers/be_utf8.rb
@@ -0,0 +1,9 @@
+RSpec::Matchers.define :be_utf8 do |_|
+ match do |actual|
+ actual.is_a?(String) && actual.encoding == Encoding.find('UTF-8')
+ end
+
+ description do
+ "be a String with encoding UTF-8"
+ end
+end
diff --git a/spec/support/matchers/have_gitlab_http_status.rb b/spec/support/matchers/have_gitlab_http_status.rb
new file mode 100644
index 00000000000..3198f1b9edd
--- /dev/null
+++ b/spec/support/matchers/have_gitlab_http_status.rb
@@ -0,0 +1,14 @@
+RSpec::Matchers.define :have_gitlab_http_status do |expected|
+ match do |actual|
+ expect(actual).to have_http_status(expected)
+ end
+
+ description do
+ "respond with numeric status code #{expected}"
+ end
+
+ failure_message do |actual|
+ "expected the response to have status code #{expected.inspect}" \
+ " but it was #{actual.response_code}. The response was: #{actual.body}"
+ end
+end
diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb
index bbbbaf4c5e8..7afa57fb76b 100644
--- a/spec/support/matchers/markdown_matchers.rb
+++ b/spec/support/matchers/markdown_matchers.rb
@@ -17,7 +17,7 @@ module MarkdownMatchers
image = actual.at_css('img[alt="Relative Image"]')
expect(link['href']).to end_with('master/doc/README.md')
- expect(image['src']).to end_with('master/app/assets/images/touch-icon-ipad.png')
+ expect(image['data-src']).to end_with('master/app/assets/images/touch-icon-ipad.png')
end
end
@@ -70,7 +70,7 @@ module MarkdownMatchers
# GollumTagsFilter
matcher :parse_gollum_tags do
def have_image(src)
- have_css("img[src$='#{src}']")
+ have_css("img[data-src$='#{src}']")
end
prefix = '/namespace1/gitlabhq/wikis'
diff --git a/spec/support/merge_request_helpers.rb b/spec/support/merge_request_helpers.rb
index 326b85eabd0..772adff4626 100644
--- a/spec/support/merge_request_helpers.rb
+++ b/spec/support/merge_request_helpers.rb
@@ -1,6 +1,6 @@
module MergeRequestHelpers
def visit_merge_requests(project, opts = {})
- visit namespace_project_merge_requests_path project.namespace, project, opts
+ visit project_merge_requests_path project, opts
end
def first_merge_request
diff --git a/spec/support/prepare-gitlab-git-test-for-commit b/spec/support/prepare-gitlab-git-test-for-commit
new file mode 100755
index 00000000000..3047786a599
--- /dev/null
+++ b/spec/support/prepare-gitlab-git-test-for-commit
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+abort unless [
+ system('spec/support/generate-seed-repo-rb', out: 'spec/support/seed_repo.rb'),
+ system('spec/support/unpack-gitlab-git-test')
+].all?
+
+exit if ARGV.first != '--check-for-changes'
+
+git_status = IO.popen(%w[git status --porcelain], &:read)
+abort unless $?.success?
+
+puts git_status
+
+if git_status.lines.grep(%r{^.. spec/support/gitlab-git-test.git}).any?
+ abort "error: detected changes in gitlab-git-test.git"
+end
diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb
new file mode 100644
index 00000000000..016e16fc8d4
--- /dev/null
+++ b/spec/support/prometheus/additional_metrics_shared_examples.rb
@@ -0,0 +1,101 @@
+RSpec.shared_examples 'additional metrics query' do
+ include Prometheus::MetricBuilders
+
+ let(:metric_group_class) { Gitlab::Prometheus::MetricGroup }
+ let(:metric_class) { Gitlab::Prometheus::Metric }
+
+ let(:metric_names) { %w{metric_a metric_b} }
+
+ let(:query_range_result) do
+ [{ 'metric': {}, 'values': [[1488758662.506, '0.00002996364761904785'], [1488758722.506, '0.00003090239047619091']] }]
+ end
+
+ before do
+ allow(client).to receive(:label_values).and_return(metric_names)
+ allow(metric_group_class).to receive(:all).and_return([simple_metric_group(metrics: [simple_metric])])
+ end
+
+ context 'with one group where two metrics is found' do
+ before do
+ allow(metric_group_class).to receive(:all).and_return([simple_metric_group])
+ end
+
+ context 'some queries return results' do
+ before do
+ allow(client).to receive(:query_range).with('query_range_a', any_args).and_return(query_range_result)
+ allow(client).to receive(:query_range).with('query_range_b', any_args).and_return(query_range_result)
+ allow(client).to receive(:query_range).with('query_range_empty', any_args).and_return([])
+ end
+
+ it 'return group data only for queries with results' do
+ expected = [
+ {
+ group: 'name',
+ priority: 1,
+ metrics: [
+ {
+ title: 'title', weight: 1, y_label: 'Values', queries: [
+ { query_range: 'query_range_a', result: query_range_result },
+ { query_range: 'query_range_b', label: 'label', unit: 'unit', result: query_range_result }
+ ]
+ }
+ ]
+ }
+ ]
+
+ expect(query_result).to match_schema('prometheus/additional_metrics_query_result')
+ expect(query_result).to eq(expected)
+ end
+ end
+ end
+
+ context 'with two groups with one metric each' do
+ let(:metrics) { [simple_metric(queries: [simple_query])] }
+ before do
+ allow(metric_group_class).to receive(:all).and_return(
+ [
+ simple_metric_group(name: 'group_a', metrics: [simple_metric(queries: [simple_query])]),
+ simple_metric_group(name: 'group_b', metrics: [simple_metric(title: 'title_b', queries: [simple_query('b')])])
+ ])
+ allow(client).to receive(:label_values).and_return(metric_names)
+ end
+
+ context 'both queries return results' do
+ before do
+ allow(client).to receive(:query_range).with('query_range_a', any_args).and_return(query_range_result)
+ allow(client).to receive(:query_range).with('query_range_b', any_args).and_return(query_range_result)
+ end
+
+ it 'return group data both queries' do
+ queries_with_result_a = { queries: [{ query_range: 'query_range_a', result: query_range_result }] }
+ queries_with_result_b = { queries: [{ query_range: 'query_range_b', result: query_range_result }] }
+
+ expect(query_result).to match_schema('prometheus/additional_metrics_query_result')
+
+ expect(query_result.count).to eq(2)
+ expect(query_result).to all(satisfy { |r| r[:metrics].count == 1 })
+
+ expect(query_result[0][:metrics].first).to include(queries_with_result_a)
+ expect(query_result[1][:metrics].first).to include(queries_with_result_b)
+ end
+ end
+
+ context 'one query returns result' do
+ before do
+ allow(client).to receive(:query_range).with('query_range_a', any_args).and_return(query_range_result)
+ allow(client).to receive(:query_range).with('query_range_b', any_args).and_return([])
+ end
+
+ it 'return group data only for query with results' do
+ queries_with_result = { queries: [{ query_range: 'query_range_a', result: query_range_result }] }
+
+ expect(query_result).to match_schema('prometheus/additional_metrics_query_result')
+
+ expect(query_result.count).to eq(1)
+ expect(query_result).to all(satisfy { |r| r[:metrics].count == 1 })
+
+ expect(query_result.first[:metrics].first).to include(queries_with_result)
+ end
+ end
+ end
+end
diff --git a/spec/support/prometheus/metric_builders.rb b/spec/support/prometheus/metric_builders.rb
new file mode 100644
index 00000000000..c8d056d3fc8
--- /dev/null
+++ b/spec/support/prometheus/metric_builders.rb
@@ -0,0 +1,27 @@
+module Prometheus
+ module MetricBuilders
+ def simple_query(suffix = 'a', **opts)
+ { query_range: "query_range_#{suffix}" }.merge(opts)
+ end
+
+ def simple_queries
+ [simple_query, simple_query('b', label: 'label', unit: 'unit')]
+ end
+
+ def simple_metric(title: 'title', required_metrics: [], queries: [simple_query])
+ Gitlab::Prometheus::Metric.new(title: title, required_metrics: required_metrics, weight: 1, queries: queries)
+ end
+
+ def simple_metrics(added_metric_name: 'metric_a')
+ [
+ simple_metric(required_metrics: %W(#{added_metric_name} metric_b), queries: simple_queries),
+ simple_metric(required_metrics: [added_metric_name], queries: [simple_query('empty')]),
+ simple_metric(required_metrics: %w{metric_c})
+ ]
+ end
+
+ def simple_metric_group(name: 'name', metrics: simple_metrics)
+ Gitlab::Prometheus::MetricGroup.new(name: name, priority: 1, metrics: metrics)
+ end
+ end
+end
diff --git a/spec/support/prometheus_helpers.rb b/spec/support/prometheus_helpers.rb
index 6b9ebcf2bb3..4212be2cc88 100644
--- a/spec/support/prometheus_helpers.rb
+++ b/spec/support/prometheus_helpers.rb
@@ -36,6 +36,19 @@ module PrometheusHelpers
"https://prometheus.example.com/api/v1/query_range?#{query}"
end
+ def prometheus_label_values_url(name)
+ "https://prometheus.example.com/api/v1/label/#{name}/values"
+ end
+
+ def prometheus_series_url(*matches, start: 8.hours.ago, stop: Time.now)
+ query = {
+ match: matches,
+ start: start.to_f,
+ end: stop.to_f
+ }.to_query
+ "https://prometheus.example.com/api/v1/series?#{query}"
+ end
+
def stub_prometheus_request(url, body: {}, status: 200)
WebMock.stub_request(:get, url)
.to_return({
@@ -85,6 +98,19 @@ module PrometheusHelpers
def prometheus_data(last_update: Time.now.utc)
{
success: true,
+ data: {
+ memory_values: prometheus_values_body('matrix').dig(:data, :result),
+ memory_current: prometheus_value_body('vector').dig(:data, :result),
+ cpu_values: prometheus_values_body('matrix').dig(:data, :result),
+ cpu_current: prometheus_value_body('vector').dig(:data, :result)
+ },
+ last_update: last_update
+ }
+ end
+
+ def prometheus_metrics_data(last_update: Time.now.utc)
+ {
+ success: true,
metrics: {
memory_values: prometheus_values_body('matrix').dig(:data, :result),
memory_current: prometheus_value_body('vector').dig(:data, :result),
@@ -140,4 +166,37 @@ module PrometheusHelpers
}
}
end
+
+ def prometheus_label_values
+ {
+ 'status': 'success',
+ 'data': %w(job_adds job_controller_rate_limiter_use job_depth job_queue_latency job_work_duration_sum up)
+ }
+ end
+
+ def prometheus_series(name)
+ {
+ 'status': 'success',
+ 'data': [
+ {
+ '__name__': name,
+ 'container_name': 'gitlab',
+ 'environment': 'mattermost',
+ 'id': '/docker/9953982f95cf5010dfc59d7864564d5f188aaecddeda343699783009f89db667',
+ 'image': 'gitlab/gitlab-ce:8.15.4-ce.1',
+ 'instance': 'minikube',
+ 'job': 'kubernetes-nodes',
+ 'name': 'k8s_gitlab.e6611886_mattermost-4210310111-77z8r_gitlab_2298ae6b-da24-11e6-baee-8e7f67d0eb3a_43536cb6',
+ 'namespace': 'gitlab',
+ 'pod_name': 'mattermost-4210310111-77z8r'
+ },
+ {
+ '__name__': name,
+ 'id': '/docker',
+ 'instance': 'minikube',
+ 'job': 'kubernetes-nodes'
+ }
+ ]
+ }
+ end
end
diff --git a/spec/support/protected_tags/access_control_ce_shared_examples.rb b/spec/support/protected_tags/access_control_ce_shared_examples.rb
index 61fb1ffc47a..2770cdcbefc 100644
--- a/spec/support/protected_tags/access_control_ce_shared_examples.rb
+++ b/spec/support/protected_tags/access_control_ce_shared_examples.rb
@@ -1,7 +1,7 @@
RSpec.shared_examples "protected tags > access control > CE" do
ProtectedTag::CreateAccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
it "allows creating protected tags that #{access_type_name} can create" do
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('master')
@@ -22,7 +22,7 @@ RSpec.shared_examples "protected tags > access control > CE" do
end
it "allows updating protected tags so that #{access_type_name} can create them" do
- visit namespace_project_protected_tags_path(project.namespace, project)
+ visit project_protected_tags_path(project)
set_protected_tag_name('master')
diff --git a/spec/lib/gitlab/redis_spec.rb b/spec/support/redis/redis_shared_examples.rb
index 593aa5038ad..f9552e41894 100644
--- a/spec/lib/gitlab/redis_spec.rb
+++ b/spec/support/redis/redis_shared_examples.rb
@@ -1,12 +1,10 @@
-require 'spec_helper'
-
-describe Gitlab::Redis do
+RSpec.shared_examples "redis_shared_examples" do
include StubENV
- let(:config) { 'config/resque.yml' }
+ let(:test_redis_url) { "redis://redishost:#{redis_port}"}
before(:each) do
- stub_env('GITLAB_REDIS_CONFIG_FILE', Rails.root.join(config).to_s)
+ stub_env(environment_config_file_name, Rails.root.join(config_file_name))
clear_raw_config
end
@@ -26,46 +24,40 @@ describe Gitlab::Redis do
end
context 'when url contains unix socket reference' do
- let(:config_old) { 'spec/fixtures/config/redis_old_format_socket.yml' }
- let(:config_new) { 'spec/fixtures/config/redis_new_format_socket.yml' }
-
context 'with old format' do
- let(:config) { config_old }
+ let(:config_file_name) { config_old_format_socket }
it 'returns path key instead' do
- is_expected.to include(path: '/path/to/old/redis.sock')
+ is_expected.to include(path: old_socket_path)
is_expected.not_to have_key(:url)
end
end
context 'with new format' do
- let(:config) { config_new }
+ let(:config_file_name) { config_new_format_socket }
it 'returns path key instead' do
- is_expected.to include(path: '/path/to/redis.sock')
+ is_expected.to include(path: new_socket_path)
is_expected.not_to have_key(:url)
end
end
end
context 'when url is host based' do
- let(:config_old) { 'spec/fixtures/config/redis_old_format_host.yml' }
- let(:config_new) { 'spec/fixtures/config/redis_new_format_host.yml' }
-
context 'with old format' do
- let(:config) { config_old }
+ let(:config_file_name) { config_old_format_host }
it 'returns hash with host, port, db, and password' do
- is_expected.to include(host: 'localhost', password: 'mypassword', port: 6379, db: 99)
+ is_expected.to include(host: 'localhost', password: 'mypassword', port: redis_port, db: redis_database)
is_expected.not_to have_key(:url)
end
end
context 'with new format' do
- let(:config) { config_new }
+ let(:config_file_name) { config_new_format_host }
it 'returns hash with host, port, db, and password' do
- is_expected.to include(host: 'localhost', password: 'mynewpassword', port: 6379, db: 99)
+ is_expected.to include(host: 'localhost', password: 'mynewpassword', port: redis_port, db: redis_database)
is_expected.not_to have_key(:url)
end
end
@@ -73,30 +65,22 @@ describe Gitlab::Redis do
end
describe '.url' do
- it 'withstands mutation' do
- url1 = described_class.url
- url2 = described_class.url
- url1 << 'foobar'
-
- expect(url2).not_to end_with('foobar')
- end
-
context 'when yml file with env variable' do
- let(:config) { 'spec/fixtures/config/redis_config_with_env.yml' }
+ let(:config_file_name) { config_with_environment_variable_inside }
before do
- stub_env('TEST_GITLAB_REDIS_URL', 'redis://redishost:6379')
+ stub_env(config_env_variable_url, test_redis_url)
end
it 'reads redis url from env variable' do
- expect(described_class.url).to eq 'redis://redishost:6379'
+ expect(described_class.url).to eq test_redis_url
end
end
end
describe '._raw_config' do
subject { described_class._raw_config }
- let(:config) { '/var/empty/doesnotexist' }
+ let(:config_file_name) { '/var/empty/doesnotexist' }
it 'should be frozen' do
expect(subject).to be_frozen
@@ -105,6 +89,12 @@ describe Gitlab::Redis do
it 'returns false when the file does not exist' do
expect(subject).to eq(false)
end
+
+ it "returns false when the filename can't be determined" do
+ expect(described_class).to receive(:config_file_name).and_return(nil)
+
+ expect(subject).to eq(false)
+ end
end
describe '.with' do
@@ -124,7 +114,7 @@ describe Gitlab::Redis do
it 'instantiates a connection pool with size 5' do
expect(ConnectionPool).to receive(:new).with(size: 5).and_call_original
- described_class.with { |_redis| true }
+ described_class.with { |_redis_shared_example| true }
end
end
@@ -137,7 +127,7 @@ describe Gitlab::Redis do
it 'instantiates a connection pool with a size based on the concurrency of the worker' do
expect(ConnectionPool).to receive(:new).with(size: 18 + 5).and_call_original
- described_class.with { |_redis| true }
+ described_class.with { |_redis_shared_example| true }
end
end
end
@@ -146,16 +136,16 @@ describe Gitlab::Redis do
subject { described_class.new(Rails.env).sentinels }
context 'when sentinels are defined' do
- let(:config) { 'spec/fixtures/config/redis_new_format_host.yml' }
+ let(:config_file_name) { config_new_format_host }
it 'returns an array of hashes with host and port keys' do
- is_expected.to include(host: 'localhost', port: 26380)
- is_expected.to include(host: 'slave2', port: 26381)
+ is_expected.to include(host: 'localhost', port: sentinel_port)
+ is_expected.to include(host: 'slave2', port: sentinel_port)
end
end
context 'when sentinels are not defined' do
- let(:config) { 'spec/fixtures/config/redis_old_format_host.yml' }
+ let(:config_file_name) { config_old_format_host }
it 'returns nil' do
is_expected.to be_nil
@@ -167,7 +157,7 @@ describe Gitlab::Redis do
subject { described_class.new(Rails.env).sentinels? }
context 'when sentinels are defined' do
- let(:config) { 'spec/fixtures/config/redis_new_format_host.yml' }
+ let(:config_file_name) { config_new_format_host }
it 'returns true' do
is_expected.to be_truthy
@@ -175,7 +165,7 @@ describe Gitlab::Redis do
end
context 'when sentinels are not defined' do
- let(:config) { 'spec/fixtures/config/redis_old_format_host.yml' }
+ let(:config_file_name) { config_old_format_host }
it 'returns false' do
is_expected.to be_falsey
@@ -187,12 +177,12 @@ describe Gitlab::Redis do
it 'returns default redis url when no config file is present' do
expect(subject).to receive(:fetch_config) { false }
- expect(subject.send(:raw_config_hash)).to eq(url: Gitlab::Redis::DEFAULT_REDIS_URL)
+ expect(subject.send(:raw_config_hash)).to eq(url: class_redis_url )
end
it 'returns old-style single url config in a hash' do
- expect(subject).to receive(:fetch_config) { 'redis://myredis:6379' }
- expect(subject.send(:raw_config_hash)).to eq(url: 'redis://myredis:6379')
+ expect(subject).to receive(:fetch_config) { test_redis_url }
+ expect(subject.send(:raw_config_hash)).to eq(url: test_redis_url)
end
end
@@ -200,7 +190,13 @@ describe Gitlab::Redis do
it 'returns false when no config file is present' do
allow(described_class).to receive(:_raw_config) { false }
- expect(subject.send(:fetch_config)).to be_falsey
+ expect(subject.send(:fetch_config)).to eq false
+ end
+
+ it 'returns false when config file is present but has invalid YAML' do
+ allow(described_class).to receive(:_raw_config) { "# development: true" }
+
+ expect(subject.send(:fetch_config)).to eq false
end
end
diff --git a/spec/support/routing_helpers.rb b/spec/support/routing_helpers.rb
new file mode 100644
index 00000000000..af1f4760804
--- /dev/null
+++ b/spec/support/routing_helpers.rb
@@ -0,0 +1,3 @@
+RSpec.configure do |config|
+ config.include GitlabRoutingHelper
+end
diff --git a/spec/support/seed_helper.rb b/spec/support/seed_helper.rb
index 47b5f556e66..8731847592b 100644
--- a/spec/support/seed_helper.rb
+++ b/spec/support/seed_helper.rb
@@ -9,7 +9,7 @@ TEST_MUTABLE_REPO_PATH = 'mutable-repo.git'.freeze
TEST_BROKEN_REPO_PATH = 'broken-repo.git'.freeze
module SeedHelper
- GITLAB_GIT_TEST_REPO_URL = ENV.fetch('GITLAB_GIT_TEST_REPO_URL', 'https://gitlab.com/gitlab-org/gitlab-git-test.git').freeze
+ GITLAB_GIT_TEST_REPO_URL = File.expand_path('../gitlab-git-test.git', __FILE__).freeze
def ensure_seeds
if File.exist?(SEED_STORAGE_PATH)
diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
index dcc562c684b..855051921f0 100644
--- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
+++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-shared_examples "migrating a deleted user's associated records to the ghost user" do |record_class|
+shared_examples "migrating a deleted user's associated records to the ghost user" do |record_class, fields|
record_class_name = record_class.to_s.titleize.downcase
let(:project) { create(:project) }
@@ -11,6 +11,7 @@ shared_examples "migrating a deleted user's associated records to the ghost user
context "for a #{record_class_name} the user has created" do
let!(:record) { created_record }
+ let(:migrated_fields) { fields || [:author] }
it "does not delete the #{record_class_name}" do
service.execute
@@ -18,22 +19,20 @@ shared_examples "migrating a deleted user's associated records to the ghost user
expect(record_class.find_by_id(record.id)).to be_present
end
- it "migrates the #{record_class_name} so that the 'Ghost User' is the #{record_class_name} owner" do
+ it "blocks the user before migrating #{record_class_name}s to the 'Ghost User'" do
service.execute
- migrated_record = record_class.find_by_id(record.id)
-
- if migrated_record.respond_to?(:author)
- expect(migrated_record.author).to eq(User.ghost)
- else
- expect(migrated_record.send(author_alias)).to eq(User.ghost)
- end
+ expect(user).to be_blocked
end
- it "blocks the user before migrating #{record_class_name}s to the 'Ghost User'" do
+ it 'migrates all associated fields to te "Ghost user"' do
service.execute
- expect(user).to be_blocked
+ migrated_record = record_class.find_by_id(record.id)
+
+ migrated_fields.each do |field|
+ expect(migrated_record.public_send(field)).to eq(User.ghost)
+ end
end
context "race conditions" do
diff --git a/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
new file mode 100644
index 00000000000..96c821b26f7
--- /dev/null
+++ b/spec/support/shared_examples/features/issuable_sidebar_shared_examples.rb
@@ -0,0 +1,9 @@
+shared_examples 'issue sidebar stays collapsed on mobile' do
+ before do
+ resize_screen_xs
+ end
+
+ it 'keeps the sidebar collapsed' do
+ expect(page).not_to have_css('.right-sidebar.right-sidebar-collapsed')
+ end
+end
diff --git a/spec/support/protected_branches/access_control_ce_shared_examples.rb b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
index 71f622326a5..72bb0f2e9b9 100644
--- a/spec/support/protected_branches/access_control_ce_shared_examples.rb
+++ b/spec/support/shared_examples/features/protected_branches_access_control_ce.rb
@@ -1,11 +1,11 @@
-RSpec.shared_examples "protected branches > access control > CE" do
+shared_examples "protected branches > access control > CE" do
ProtectedBranch::PushAccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
it "allows creating protected branches that #{access_type_name} can push to" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('master')
- within('.new_protected_branch') do
+ within('.js-new-protected-branch') do
allowed_to_push_button = find(".js-allowed-to-push")
unless allowed_to_push_button.text == access_type_name
@@ -21,7 +21,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
end
it "allows updating protected branches so that #{access_type_name} can push to them" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('master')
@@ -46,11 +46,11 @@ RSpec.shared_examples "protected branches > access control > CE" do
ProtectedBranch::MergeAccessLevel.human_access_levels.each do |(access_type_id, access_type_name)|
it "allows creating protected branches that #{access_type_name} can merge to" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('master')
- within('.new_protected_branch') do
+ within('.js-new-protected-branch') do
allowed_to_merge_button = find(".js-allowed-to-merge")
unless allowed_to_merge_button.text == access_type_name
@@ -66,7 +66,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
end
it "allows updating protected branches so that #{access_type_name} can merge to them" do
- visit namespace_project_protected_branches_path(project.namespace, project)
+ visit project_protected_branches_path(project)
set_protected_branch_name('master')
diff --git a/spec/support/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb
index 3481749a7f0..226277411d6 100644
--- a/spec/support/api/status_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb
@@ -9,7 +9,7 @@ shared_examples_for '400 response' do
end
it 'returns 400' do
- expect(response).to have_http_status(400)
+ expect(response).to have_gitlab_http_status(400)
end
end
@@ -20,7 +20,7 @@ shared_examples_for '403 response' do
end
it 'returns 403' do
- expect(response).to have_http_status(403)
+ expect(response).to have_gitlab_http_status(403)
end
end
@@ -32,7 +32,7 @@ shared_examples_for '404 response' do
end
it 'returns 404' do
- expect(response).to have_http_status(404)
+ expect(response).to have_gitlab_http_status(404)
expect(json_response).to be_an Object
if message.present?
diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb
index 575d3451150..d143014692d 100644
--- a/spec/support/sidekiq.rb
+++ b/spec/support/sidekiq.rb
@@ -3,3 +3,13 @@ require 'sidekiq/testing/inline'
Sidekiq::Testing.server_middleware do |chain|
chain.add Gitlab::SidekiqStatus::ServerMiddleware
end
+
+RSpec.configure do |config|
+ config.after(:each, :sidekiq) do
+ Sidekiq::Worker.clear_all
+ end
+
+ config.after(:each, :sidekiq, :redis) do
+ Sidekiq.redis { |redis| redis.flushdb }
+ end
+end
diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb
index 044c09d5fde..6accf16bea4 100644
--- a/spec/support/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/slack_mattermost_notifications_shared_examples.rb
@@ -78,7 +78,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do
wiki_page_service = WikiPages::CreateService.new(project, user, opts)
@wiki_page = wiki_page_service.execute
- @wiki_page_sample_data = wiki_page_service.hook_data(@wiki_page, 'create')
+ @wiki_page_sample_data = Gitlab::DataBuilder::WikiPage.build(@wiki_page, user, 'create')
end
it "calls Slack/Mattermost API for push events" do
diff --git a/spec/support/sorting_helper.rb b/spec/support/sorting_helper.rb
new file mode 100644
index 00000000000..577518d726c
--- /dev/null
+++ b/spec/support/sorting_helper.rb
@@ -0,0 +1,18 @@
+# Helper allows you to sort items
+#
+# Params
+# value - value for sorting
+#
+# Usage:
+# include SortingHelper
+#
+# sorting_by('Oldest updated')
+#
+module SortingHelper
+ def sorting_by(value)
+ find('button.dropdown-toggle').click
+ page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
+ click_link value
+ end
+ end
+end
diff --git a/spec/support/stub_configuration.rb b/spec/support/stub_configuration.rb
index 48f454c7187..516f8878679 100644
--- a/spec/support/stub_configuration.rb
+++ b/spec/support/stub_configuration.rb
@@ -4,29 +4,38 @@ module StubConfiguration
# Stubbing both of these because we're not yet consistent with how we access
# current application settings
- allow_any_instance_of(ApplicationSetting).to receive_messages(messages)
+ allow_any_instance_of(ApplicationSetting).to receive_messages(to_settings(messages))
allow(Gitlab::CurrentSettings.current_application_settings)
- .to receive_messages(messages)
+ .to receive_messages(to_settings(messages))
+ end
+
+ def stub_not_protect_default_branch
+ stub_application_setting(
+ default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
def stub_config_setting(messages)
- allow(Gitlab.config.gitlab).to receive_messages(messages)
+ allow(Gitlab.config.gitlab).to receive_messages(to_settings(messages))
end
def stub_gravatar_setting(messages)
- allow(Gitlab.config.gravatar).to receive_messages(messages)
+ allow(Gitlab.config.gravatar).to receive_messages(to_settings(messages))
end
def stub_incoming_email_setting(messages)
- allow(Gitlab.config.incoming_email).to receive_messages(messages)
+ allow(Gitlab.config.incoming_email).to receive_messages(to_settings(messages))
end
def stub_mattermost_setting(messages)
- allow(Gitlab.config.mattermost).to receive_messages(messages)
+ allow(Gitlab.config.mattermost).to receive_messages(to_settings(messages))
end
def stub_omniauth_setting(messages)
- allow(Gitlab.config.omniauth).to receive_messages(messages)
+ allow(Gitlab.config.omniauth).to receive_messages(to_settings(messages))
+ end
+
+ def stub_backup_setting(messages)
+ allow(Gitlab.config.backup).to receive_messages(to_settings(messages))
end
private
@@ -49,4 +58,15 @@ module StubConfiguration
messages[predicate.to_sym] = messages[key.to_sym]
end
end
+
+ # Support nested hashes by converting all values into Settingslogic objects
+ def to_settings(hash)
+ hash.transform_values do |value|
+ if value.is_a? Hash
+ Settingslogic.new(value.deep_stringify_keys)
+ else
+ value
+ end
+ end
+ end
end
diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb
index 18597b5c71f..b8928867174 100644
--- a/spec/support/stub_env.rb
+++ b/spec/support/stub_env.rb
@@ -1,7 +1,33 @@
+# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
module StubENV
- def stub_env(key, value)
- allow(ENV).to receive(:[]).and_call_original unless @env_already_stubbed
- @env_already_stubbed ||= true
+ def stub_env(key_or_hash, value = nil)
+ init_stub unless env_stubbed?
+ if key_or_hash.is_a? Hash
+ key_or_hash.each { |k, v| add_stubbed_value(k, v) }
+ else
+ add_stubbed_value key_or_hash, value
+ end
+ end
+
+ private
+
+ STUBBED_KEY = '__STUBBED__'.freeze
+
+ def add_stubbed_value(key, value)
allow(ENV).to receive(:[]).with(key).and_return(value)
+ allow(ENV).to receive(:fetch).with(key).and_return(value)
+ allow(ENV).to receive(:fetch).with(key, anything()) do |_, default_val|
+ value || default_val
+ end
+ end
+
+ def env_stubbed?
+ ENV[STUBBED_KEY]
+ end
+
+ def init_stub
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:fetch).and_call_original
+ add_stubbed_value(STUBBED_KEY, true)
end
end
diff --git a/spec/support/stub_feature_flags.rb b/spec/support/stub_feature_flags.rb
new file mode 100644
index 00000000000..b96338bf548
--- /dev/null
+++ b/spec/support/stub_feature_flags.rb
@@ -0,0 +1,8 @@
+module StubFeatureFlags
+ def stub_feature_flags(features)
+ features.each do |feature_name, enabled|
+ allow(Feature).to receive(:enabled?).with(feature_name) { enabled }
+ allow(Feature).to receive(:enabled?).with(feature_name.to_s) { enabled }
+ end
+ end
+end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 1c5267c290b..86f9568c12e 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -5,6 +5,7 @@ module TestEnv
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
+ 'signed-commits' => '5d4a1cb',
'not-merged-branch' => 'b83d6e3',
'branch-merged' => '498214d',
'empty-branch' => '7efb185',
@@ -41,7 +42,8 @@ module TestEnv
'csv' => '3dd0896',
'v1.1.0' => 'b83d6e3',
'add-ipython-files' => '93ee732',
- 'add-pdf-file' => 'e774ebd'
+ 'add-pdf-file' => 'e774ebd',
+ 'add-pdf-text-binary' => '79faa7b'
}.freeze
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
@@ -69,7 +71,7 @@ module TestEnv
# Setup GitLab shell for test instance
setup_gitlab_shell
- setup_gitaly if Gitlab::GitalyClient.enabled?
+ setup_gitaly
# Create repository for FactoryGirl.create(:project)
setup_factory_repo
@@ -120,18 +122,21 @@ module TestEnv
end
def setup_gitlab_shell
- unless File.directory?(Gitlab.config.gitlab_shell.path)
- unless system('rake', 'gitlab:shell:install')
- raise 'Can`t clone gitlab-shell'
- end
+ shell_needs_update = component_needs_update?(Gitlab.config.gitlab_shell.path,
+ Gitlab::Shell.version_required)
+
+ unless !shell_needs_update || system('rake', 'gitlab:shell:install')
+ raise 'Can`t clone gitlab-shell'
end
end
def setup_gitaly
socket_path = Gitlab::GitalyClient.address('default').sub(/\Aunix:/, '')
gitaly_dir = File.dirname(socket_path)
+ gitaly_needs_update = component_needs_update?(gitaly_dir,
+ Gitlab::GitalyClient.expected_server_version)
- unless !gitaly_needs_update?(gitaly_dir) || system('rake', "gitlab:gitaly:install[#{gitaly_dir}]")
+ unless !gitaly_needs_update || system('rake', "gitlab:gitaly:install[#{gitaly_dir}]")
raise "Can't clone gitaly"
end
@@ -142,7 +147,7 @@ module TestEnv
gitaly_exec = File.join(gitaly_dir, 'gitaly')
gitaly_config = File.join(gitaly_dir, 'config.toml')
log_file = Rails.root.join('log/gitaly-test.log').to_s
- @gitaly_pid = spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file)
+ @gitaly_pid = Bundler.with_original_env { spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file) }
end
def stop_gitaly
@@ -203,6 +208,7 @@ module TestEnv
# Otherwise they'd be created by the first test, often timing out and
# causing a transient test failure
def eager_load_driver_server
+ return unless ENV['CI']
return unless defined?(Capybara)
puts "Starting the Capybara driver server..."
@@ -261,13 +267,13 @@ module TestEnv
end
end
- def gitaly_needs_update?(gitaly_dir)
- gitaly_version = File.read(File.join(gitaly_dir, 'VERSION')).strip
+ def component_needs_update?(component_folder, expected_version)
+ version = File.read(File.join(component_folder, 'VERSION')).strip
# Notice that this will always yield true when using branch versions
# (`=branch_name`), but that actually makes sure the server is always based
# on the latest branch revision.
- gitaly_version != Gitlab::GitalyClient.expected_server_version
+ version != expected_version
rescue Errno::ENOENT
true
end
diff --git a/spec/support/unique_ip_check_shared_examples.rb b/spec/support/unique_ip_check_shared_examples.rb
index 1986d202c4a..ff0b47899f5 100644
--- a/spec/support/unique_ip_check_shared_examples.rb
+++ b/spec/support/unique_ip_check_shared_examples.rb
@@ -1,7 +1,9 @@
shared_context 'unique ips sign in limit' do
include StubENV
before(:each) do
- Gitlab::Redis.with(&:flushall)
+ Gitlab::Redis::Cache.with(&:flushall)
+ Gitlab::Redis::Queues.with(&:flushall)
+ Gitlab::Redis::SharedState.with(&:flushall)
end
before do
diff --git a/spec/support/unpack-gitlab-git-test b/spec/support/unpack-gitlab-git-test
new file mode 100755
index 00000000000..d5b4912457d
--- /dev/null
+++ b/spec/support/unpack-gitlab-git-test
@@ -0,0 +1,38 @@
+#!/usr/bin/env ruby
+require 'fileutils'
+
+REPO = 'spec/support/gitlab-git-test.git'.freeze
+PACK_DIR = REPO + '/objects/pack'
+GIT = %W[git --git-dir=#{REPO}].freeze
+BASE_PACK = 'pack-691247af2a6acb0b63b73ac0cb90540e93614043'.freeze
+
+def main
+ unpack
+ # We want to store the refs in a packed-refs file because if we don't
+ # they can get mangled by filesystems.
+ abort unless system(*GIT, *%w[pack-refs --all])
+ abort unless system(*GIT, 'fsck')
+end
+
+# We don't want contributors to commit new pack files because those
+# create unnecessary churn.
+def unpack
+ pack_files = Dir[File.join(PACK_DIR, '*')].reject do |pack|
+ pack.start_with?(File.join(PACK_DIR, BASE_PACK))
+ end
+ return if pack_files.empty?
+
+ pack_files.each do |pack|
+ unless pack.end_with?('.pack')
+ FileUtils.rm(pack)
+ next
+ end
+
+ File.open(pack, 'rb') do |open_pack|
+ File.unlink(pack)
+ abort unless system(*GIT, 'unpack-objects', in: open_pack)
+ end
+ end
+end
+
+main
diff --git a/spec/tasks/gitlab/task_helpers_spec.rb b/spec/tasks/gitlab/task_helpers_spec.rb
index 91cc684d032..d34617be474 100644
--- a/spec/tasks/gitlab/task_helpers_spec.rb
+++ b/spec/tasks/gitlab/task_helpers_spec.rb
@@ -20,7 +20,6 @@ describe Gitlab::TaskHelpers do
it 'checkout the version and reset to it' do
expect(subject).to receive(:checkout_version).with(tag, clone_path)
- expect(subject).to receive(:reset_to_version).with(tag, clone_path)
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
end
@@ -31,7 +30,6 @@ describe Gitlab::TaskHelpers do
it 'checkout the version and reset to it with a branch name' do
expect(subject).to receive(:checkout_version).with(branch, clone_path)
- expect(subject).to receive(:reset_to_version).with(branch, clone_path)
subject.checkout_or_clone_version(version: version, repo: repo, target_dir: clone_path)
end
@@ -70,20 +68,11 @@ describe Gitlab::TaskHelpers do
describe '#checkout_version' do
it 'clones the repo in the target dir' do
expect(subject)
- .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} fetch --quiet])
+ .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} fetch --quiet origin #{tag}])
expect(subject)
- .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} checkout --quiet #{tag}])
+ .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} checkout -f --quiet FETCH_HEAD --])
subject.checkout_version(tag, clone_path)
end
end
-
- describe '#reset_to_version' do
- it 'resets --hard to the given version' do
- expect(subject)
- .to receive(:run_command!).with(%W[#{Gitlab.config.git.bin_path} -C #{clone_path} reset --hard #{tag}])
-
- subject.reset_to_version(tag, clone_path)
- end
- end
end
diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb
index d82dbe871d5..04ee6e9bfad 100644
--- a/spec/uploaders/attachment_uploader_spec.rb
+++ b/spec/uploaders/attachment_uploader_spec.rb
@@ -5,7 +5,7 @@ describe AttachmentUploader do
describe "#store_dir" do
it "stores in the system dir" do
- expect(uploader.store_dir).to start_with("uploads/system/user")
+ expect(uploader.store_dir).to start_with("uploads/-/system/user")
end
it "uses the old path when using object storage" do
diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb
index 201fe6949aa..1dc574699d8 100644
--- a/spec/uploaders/avatar_uploader_spec.rb
+++ b/spec/uploaders/avatar_uploader_spec.rb
@@ -5,7 +5,7 @@ describe AvatarUploader do
describe "#store_dir" do
it "stores in the system dir" do
- expect(uploader.store_dir).to start_with("uploads/system/user")
+ expect(uploader.store_dir).to start_with("uploads/-/system/user")
end
it "uses the old path when using object storage" do
diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb
index 896cb410ed5..d7c1b390f9a 100644
--- a/spec/uploaders/file_mover_spec.rb
+++ b/spec/uploaders/file_mover_spec.rb
@@ -4,11 +4,11 @@ describe FileMover do
let(:filename) { 'banana_sample.gif' }
let(:file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) }
let(:temp_description) do
- 'test ![banana_sample](/uploads/temp/secret55/banana_sample.gif) same ![banana_sample]'\
- '(/uploads/temp/secret55/banana_sample.gif)'
+ 'test ![banana_sample](/uploads/system/temp/secret55/banana_sample.gif) same ![banana_sample]'\
+ '(/uploads/system/temp/secret55/banana_sample.gif)'
end
let(:temp_file_path) { File.join('secret55', filename).to_s }
- let(:file_path) { File.join('uploads', 'personal_snippet', snippet.id.to_s, 'secret55', filename).to_s }
+ let(:file_path) { File.join('uploads', 'system', 'personal_snippet', snippet.id.to_s, 'secret55', filename).to_s }
let(:snippet) { create(:personal_snippet, description: temp_description) }
@@ -28,8 +28,8 @@ describe FileMover do
expect(snippet.reload.description)
.to eq(
- "test ![banana_sample](/uploads/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)"\
- " same ![banana_sample](/uploads/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)"
+ "test ![banana_sample](/uploads/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)"\
+ " same ![banana_sample](/uploads/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif)"
)
end
@@ -50,8 +50,8 @@ describe FileMover do
expect(snippet.reload.description)
.to eq(
- "test ![banana_sample](/uploads/temp/secret55/banana_sample.gif)"\
- " same ![banana_sample](/uploads/temp/secret55/banana_sample.gif)"
+ "test ![banana_sample](/uploads/system/temp/secret55/banana_sample.gif)"\
+ " same ![banana_sample](/uploads/system/temp/secret55/banana_sample.gif)"
)
end
diff --git a/spec/uploaders/personal_file_uploader_spec.rb b/spec/uploaders/personal_file_uploader_spec.rb
index fb92f2ae3ab..eb55e8ebd24 100644
--- a/spec/uploaders/personal_file_uploader_spec.rb
+++ b/spec/uploaders/personal_file_uploader_spec.rb
@@ -10,7 +10,7 @@ describe PersonalFileUploader do
dynamic_segment = "personal_snippet/#{snippet.id}"
- expect(described_class.absolute_path(upload)).to end_with("#{dynamic_segment}/secret/foo.jpg")
+ expect(described_class.absolute_path(upload)).to end_with("/system/#{dynamic_segment}/secret/foo.jpg")
end
end
@@ -19,7 +19,7 @@ describe PersonalFileUploader do
uploader = described_class.new(snippet, 'secret')
allow(uploader).to receive(:file).and_return(double(extension: 'txt', filename: 'file_name'))
- expected_url = "/uploads/personal_snippet/#{snippet.id}/secret/file_name"
+ expected_url = "/uploads/system/personal_snippet/#{snippet.id}/secret/file_name"
expect(uploader.to_h).to eq(
alt: 'file_name',
diff --git a/spec/views/ci/status/_badge.html.haml_spec.rb b/spec/views/ci/status/_badge.html.haml_spec.rb
index 72323da2838..de0b59f83f8 100644
--- a/spec/views/ci/status/_badge.html.haml_spec.rb
+++ b/spec/views/ci/status/_badge.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'ci/status/_badge', :view do
+describe 'ci/status/_badge' do
let(:user) { create(:user) }
let(:project) { create(:empty_project, :private) }
let(:pipeline) { create(:ci_pipeline, project: project) }
@@ -16,8 +16,7 @@ describe 'ci/status/_badge', :view do
end
it 'has link to build details page' do
- details_path = namespace_project_job_path(
- project.namespace, project, build)
+ details_path = project_job_path(project, build)
render_status(build)
diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb
index f5381a48207..f8c6cb6b5c6 100644
--- a/spec/views/projects/_home_panel.html.haml_spec.rb
+++ b/spec/views/projects/_home_panel.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/_home_panel', :view do
+describe 'projects/_home_panel' do
let(:project) { create(:empty_project, :public) }
let(:notification_settings) do
diff --git a/spec/views/projects/blob/_viewer.html.haml_spec.rb b/spec/views/projects/blob/_viewer.html.haml_spec.rb
index bbd7f98fa8d..af833168bd9 100644
--- a/spec/views/projects/blob/_viewer.html.haml_spec.rb
+++ b/spec/views/projects/blob/_viewer.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/blob/_viewer.html.haml', :view do
+describe 'projects/blob/_viewer.html.haml' do
include FakeBlobHelpers
let(:project) { build(:empty_project) }
diff --git a/spec/views/projects/commit/_commit_box.html.haml_spec.rb b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
index ab120929c6c..448b925cf34 100644
--- a/spec/views/projects/commit/_commit_box.html.haml_spec.rb
+++ b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/commit/_commit_box.html.haml', :view do
+describe 'projects/commit/_commit_box.html.haml' do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/views/projects/commit/show.html.haml_spec.rb b/spec/views/projects/commit/show.html.haml_spec.rb
index 122075cc10e..32c95c6bb0d 100644
--- a/spec/views/projects/commit/show.html.haml_spec.rb
+++ b/spec/views/projects/commit/show.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/commit/show.html.haml', :view do
+describe 'projects/commit/show.html.haml' do
let(:project) { create(:project, :repository) }
before do
@@ -21,24 +21,26 @@ describe 'projects/commit/show.html.haml', :view do
context 'inline diff view' do
before do
allow(view).to receive(:diff_view).and_return(:inline)
+ allow(view).to receive(:diff_view).and_return(:inline)
render
end
- it 'keeps container-limited' do
- expect(rendered).not_to have_selector('.limit-container-width')
+ it 'has limited width' do
+ expect(rendered).to have_selector('.limit-container-width')
end
end
context 'parallel diff view' do
before do
allow(view).to receive(:diff_view).and_return(:parallel)
+ allow(view).to receive(:fluid_layout).and_return(true)
render
end
it 'spans full width' do
- expect(rendered).to have_selector('.limit-container-width')
+ expect(rendered).not_to have_selector('.limit-container-width')
end
end
end
diff --git a/spec/views/projects/diffs/_viewer.html.haml_spec.rb b/spec/views/projects/diffs/_viewer.html.haml_spec.rb
index 32469202508..8ac32db5585 100644
--- a/spec/views/projects/diffs/_viewer.html.haml_spec.rb
+++ b/spec/views/projects/diffs/_viewer.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/diffs/_viewer.html.haml', :view do
+describe 'projects/diffs/_viewer.html.haml' do
include FakeBlobHelpers
let(:project) { create(:project, :repository) }
diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb
index d9a7ba265f8..117f48450e2 100644
--- a/spec/views/projects/jobs/show.html.haml_spec.rb
+++ b/spec/views/projects/jobs/show.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/jobs/show', :view do
+describe 'projects/jobs/show' do
let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/views/projects/merge_requests/_commits.html.haml_spec.rb b/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
index 4052dbf8df3..98c7de9b709 100644
--- a/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/merge_requests/show/_commits.html.haml' do
+describe 'projects/merge_requests/_commits.html.haml' do
include Devise::Test::ControllerHelpers
let(:user) { create(:user) }
@@ -25,10 +25,7 @@ describe 'projects/merge_requests/show/_commits.html.haml' do
render
commit = source_project.commit(merge_request.source_branch)
- href = namespace_project_commit_path(
- source_project.namespace,
- source_project,
- commit)
+ href = project_commit_path(source_project, commit)
expect(rendered).to have_link(Commit.truncate_sha(commit.sha), href: href)
end
diff --git a/spec/views/projects/merge_requests/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
index 4f698a34ab5..5770cf92b4e 100644
--- a/spec/views/projects/merge_requests/_new_submit.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/merge_requests/_new_submit.html.haml', :view do
+describe 'projects/merge_requests/creations/_new_submit.html.haml' do
let(:merge_request) { create(:merge_request) }
let!(:pipeline) { create(:ci_empty_pipeline) }
diff --git a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
index e56c0f6be03..37ce7121ccb 100644
--- a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
+++ b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/notes/_more_actions_dropdown', :view do
+describe 'projects/notes/_more_actions_dropdown' do
let(:author_user) { create(:user) }
let(:not_author_user) { create(:user) }
diff --git a/spec/views/projects/pipelines/_stage.html.haml_spec.rb b/spec/views/projects/pipelines/_stage.html.haml_spec.rb
index 9c91c4e0fbd..e40e16e742b 100644
--- a/spec/views/projects/pipelines/_stage.html.haml_spec.rb
+++ b/spec/views/projects/pipelines/_stage.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/pipelines/_stage', :view do
+describe 'projects/pipelines/_stage' do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:stage) { build(:ci_stage, pipeline: pipeline) }
diff --git a/spec/views/projects/registry/repositories/index.html.haml_spec.rb b/spec/views/projects/registry/repositories/index.html.haml_spec.rb
index ceeace3dc8d..f13b657d474 100644
--- a/spec/views/projects/registry/repositories/index.html.haml_spec.rb
+++ b/spec/views/projects/registry/repositories/index.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/registry/repositories/index', :view do
+describe 'projects/registry/repositories/index' do
let(:group) { create(:group, path: 'group') }
let(:project) { create(:empty_project, group: group, path: 'test') }
diff --git a/spec/views/projects/tags/index.html.haml_spec.rb b/spec/views/projects/tags/index.html.haml_spec.rb
index 33122365e9a..f65cd9f398f 100644
--- a/spec/views/projects/tags/index.html.haml_spec.rb
+++ b/spec/views/projects/tags/index.html.haml_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'projects/tags/index', :view do
+describe 'projects/tags/index' do
let(:project) { create(:project) }
before do
diff --git a/spec/views/shared/projects/_project.html.haml_spec.rb b/spec/views/shared/projects/_project.html.haml_spec.rb
new file mode 100644
index 00000000000..43334c2c236
--- /dev/null
+++ b/spec/views/shared/projects/_project.html.haml_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe 'shared/projects/_project.html.haml' do
+ let(:project) { create(:empty_project) }
+
+ it 'should render creator avatar if project has a creator' do
+ render 'shared/projects/project', use_creator_avatar: true, project: project
+
+ expect(rendered).to have_selector('img.avatar')
+ end
+
+ it 'should render a generic avatar if project does not have a creator' do
+ project.creator = nil
+
+ render 'shared/projects/project', use_creator_avatar: true, project: project
+
+ expect(rendered).to have_selector('.project-avatar')
+ end
+end
diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb
index 85939429feb..4f6e3474634 100644
--- a/spec/workers/background_migration_worker_spec.rb
+++ b/spec/workers/background_migration_worker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe BackgroundMigrationWorker do
+describe BackgroundMigrationWorker, :sidekiq do
describe '.perform' do
it 'performs a background migration' do
expect(Gitlab::BackgroundMigration)
@@ -10,4 +10,35 @@ describe BackgroundMigrationWorker do
described_class.new.perform('Foo', [10, 20])
end
end
+
+ describe '.perform_bulk' do
+ it 'enqueues background migrations in bulk' do
+ Sidekiq::Testing.fake! do
+ described_class.perform_bulk([['Foo', [1]], ['Foo', [2]]])
+
+ expect(described_class.jobs.count).to eq 2
+ expect(described_class.jobs).to all(include('enqueued_at'))
+ end
+ end
+ end
+
+ describe '.perform_bulk_in' do
+ context 'when delay is valid' do
+ it 'correctly schedules background migrations' do
+ Sidekiq::Testing.fake! do
+ described_class.perform_bulk_in(1.minute, [['Foo', [1]], ['Foo', [2]]])
+
+ expect(described_class.jobs.count).to eq 2
+ expect(described_class.jobs).to all(include('at'))
+ end
+ end
+ end
+
+ context 'when delay is invalid' do
+ it 'raises an ArgumentError exception' do
+ expect { described_class.perform_bulk_in(-60, [['Foo']]) }
+ .to raise_error(ArgumentError)
+ end
+ end
+ end
end
diff --git a/spec/workers/create_gpg_signature_worker_spec.rb b/spec/workers/create_gpg_signature_worker_spec.rb
new file mode 100644
index 00000000000..c6a17d77d73
--- /dev/null
+++ b/spec/workers/create_gpg_signature_worker_spec.rb
@@ -0,0 +1,47 @@
+require 'spec_helper'
+
+describe CreateGpgSignatureWorker do
+ context 'when GpgKey is found' do
+ it 'calls Commit#signature' do
+ commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
+ project = create :project
+ commit = instance_double(Commit)
+
+ allow(Project).to receive(:find_by).with(id: project.id).and_return(project)
+ allow(project).to receive(:commit).with(commit_sha).and_return(commit)
+
+ expect(commit).to receive(:signature)
+
+ described_class.new.perform(commit_sha, project.id)
+ end
+ end
+
+ context 'when Commit is not found' do
+ let(:nonexisting_commit_sha) { 'bogus' }
+ let(:project) { create :project }
+
+ it 'does not raise errors' do
+ expect { described_class.new.perform(nonexisting_commit_sha, project.id) }.not_to raise_error
+ end
+
+ it 'does not call Commit#signature' do
+ expect_any_instance_of(Commit).not_to receive(:signature)
+
+ described_class.new.perform(nonexisting_commit_sha, project.id)
+ end
+ end
+
+ context 'when Project is not found' do
+ let(:nonexisting_project_id) { -1 }
+
+ it 'does not raise errors' do
+ expect { described_class.new.perform(anything, nonexisting_project_id) }.not_to raise_error
+ end
+
+ it 'does not call Commit#signature' do
+ expect_any_instance_of(Commit).not_to receive(:signature)
+
+ described_class.new.perform(anything, nonexisting_project_id)
+ end
+ end
+end
diff --git a/spec/workers/expire_build_instance_artifacts_worker_spec.rb b/spec/workers/expire_build_instance_artifacts_worker_spec.rb
index 1d8da68883b..bed5c5e2ecb 100644
--- a/spec/workers/expire_build_instance_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_instance_artifacts_worker_spec.rb
@@ -30,20 +30,6 @@ describe ExpireBuildInstanceArtifactsWorker do
expect(build.reload.artifacts_file_identifier).to be_nil
end
end
-
- context 'when associated project was removed' do
- let(:build) do
- create(:ci_build, :artifacts, artifacts_expiry) do |build|
- build.project.pending_delete = true
- end
- end
-
- it 'does not remove artifacts' do
- expect do
- build.reload.artifacts_file
- end.not_to raise_error
- end
- end
end
context 'with not yet expired artifacts' do
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 309b3172da1..05f971dfd13 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -9,17 +9,51 @@ describe GitGarbageCollectWorker do
subject { described_class.new }
describe "#perform" do
- it "flushes ref caches when the task is 'gc'" do
- expect(subject).to receive(:command).with(:gc).and_return([:the, :command])
- expect(Gitlab::Popen).to receive(:popen)
- .with([:the, :command], project.repository.path_to_repo).and_return(["", 0])
+ shared_examples 'flushing ref caches' do |gitaly|
+ it "flushes ref caches when the task if 'gc'" do
+ expect(subject).to receive(:command).with(:gc).and_return([:the, :command])
+
+ if gitaly
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect)
+ .and_return(nil)
+ else
+ expect(Gitlab::Popen).to receive(:popen)
+ .with([:the, :command], project.repository.path_to_repo).and_return(["", 0])
+ end
+
+ expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
+ expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
+ expect_any_instance_of(Repository).to receive(:branch_count).and_call_original
+ expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
+
+ subject.perform(project.id)
+ end
+ end
+
+ context "with Gitaly turned on" do
+ it_should_behave_like 'flushing ref caches', true
+ end
+
+ context "with Gitaly turned off", skip_gitaly_mock: true do
+ it_should_behave_like 'flushing ref caches', false
+ end
- expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
- expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
- expect_any_instance_of(Repository).to receive(:branch_count).and_call_original
- expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
+ context "repack_full" do
+ it "calls Gitaly" do
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_full)
+ .and_return(nil)
- subject.perform(project.id)
+ subject.perform(project.id, :full_repack)
+ end
+ end
+
+ context "repack_incremental" do
+ it "calls Gitaly" do
+ expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_incremental)
+ .and_return(nil)
+
+ subject.perform(project.id, :incremental_repack)
+ end
end
shared_examples 'gc tasks' do
diff --git a/spec/workers/invalid_gpg_signature_update_worker_spec.rb b/spec/workers/invalid_gpg_signature_update_worker_spec.rb
new file mode 100644
index 00000000000..5972696515b
--- /dev/null
+++ b/spec/workers/invalid_gpg_signature_update_worker_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe InvalidGpgSignatureUpdateWorker do
+ context 'when GpgKey is found' do
+ it 'calls NotificationService.new.run' do
+ gpg_key = create(:gpg_key)
+ invalid_signature_updater = double(:invalid_signature_updater)
+
+ expect(Gitlab::Gpg::InvalidGpgSignatureUpdater).to receive(:new).with(gpg_key).and_return(invalid_signature_updater)
+ expect(invalid_signature_updater).to receive(:run)
+
+ described_class.new.perform(gpg_key.id)
+ end
+ end
+
+ context 'when GpgKey is not found' do
+ let(:nonexisting_gpg_key_id) { -1 }
+
+ it 'does not raise errors' do
+ expect { described_class.new.perform(nonexisting_gpg_key_id) }.not_to raise_error
+ end
+
+ it 'does not call NotificationService.new.run' do
+ expect(Gitlab::Gpg::InvalidGpgSignatureUpdater).not_to receive(:new)
+
+ described_class.new.perform(nonexisting_gpg_key_id)
+ end
+ end
+end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index cc9bc29c6cc..74a9f90195c 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -4,7 +4,7 @@ describe PostReceive do
let(:changes) { "123456 789012 refs/heads/tést\n654321 210987 refs/tags/tag" }
let(:wrongly_encoded_changes) { changes.encode("ISO-8859-1").force_encoding("UTF-8") }
let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) }
- let(:project_identifier) { "project-#{project.id}" }
+ let(:gl_repository) { "project-#{project.id}" }
let(:key) { create(:key, user: project.owner) }
let(:key_id) { key.shell_id }
@@ -19,22 +19,14 @@ describe PostReceive do
end
context 'with a non-existing project' do
- let(:project_identifier) { "project-123456789" }
+ let(:gl_repository) { "project-123456789" }
let(:error_message) do
- "Triggered hook for non-existing project with identifier \"#{project_identifier}\""
+ "Triggered hook for non-existing project with gl_repository \"#{gl_repository}\""
end
it "returns false and logs an error" do
expect(Gitlab::GitLogger).to receive(:error).with("POST-RECEIVE: #{error_message}")
- expect(described_class.new.perform(project_identifier, key_id, base64_changes)).to be(false)
- end
- end
-
- context "with an absolute path as the project identifier" do
- it "searches the project by full path" do
- expect(Project).to receive(:find_by_full_path).with(project.full_path, follow_redirects: true).and_call_original
-
- described_class.new.perform(pwd(project), key_id, base64_changes)
+ expect(described_class.new.perform(gl_repository, key_id, base64_changes)).to be(false)
end
end
@@ -49,7 +41,7 @@ describe PostReceive do
it "calls GitTagPushService" do
expect_any_instance_of(GitPushService).to receive(:execute).and_return(true)
expect_any_instance_of(GitTagPushService).not_to receive(:execute)
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
end
@@ -59,7 +51,7 @@ describe PostReceive do
it "calls GitTagPushService" do
expect_any_instance_of(GitPushService).not_to receive(:execute)
expect_any_instance_of(GitTagPushService).to receive(:execute).and_return(true)
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
end
@@ -69,12 +61,12 @@ describe PostReceive do
it "does not call any of the services" do
expect_any_instance_of(GitPushService).not_to receive(:execute)
expect_any_instance_of(GitTagPushService).not_to receive(:execute)
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
end
context "gitlab-ci.yml" do
- subject { described_class.new.perform(project_identifier, key_id, base64_changes) }
+ subject { described_class.new.perform(gl_repository, key_id, base64_changes) }
context "creates a Ci::Pipeline for every change" do
before do
@@ -82,6 +74,7 @@ describe PostReceive do
OpenStruct.new(id: '123456')
end
allow_any_instance_of(Ci::CreatePipelineService).to receive(:branch?).and_return(true)
+ allow_any_instance_of(Repository).to receive(:ref_exists?).and_return(true)
stub_ci_pipeline_to_return_yaml_file
end
@@ -111,7 +104,7 @@ describe PostReceive do
it 'calls SystemHooksService' do
expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true)
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
end
end
@@ -119,7 +112,7 @@ describe PostReceive do
context "webhook" do
it "fetches the correct project" do
expect(Project).to receive(:find_by).with(id: project.id.to_s)
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
it "does not run if the author is not in the project" do
@@ -129,7 +122,7 @@ describe PostReceive do
expect(project).not_to receive(:execute_hooks)
- expect(described_class.new.perform(project_identifier, key_id, base64_changes)).to be_falsey
+ expect(described_class.new.perform(gl_repository, key_id, base64_changes)).to be_falsey
end
it "asks the project to trigger all hooks" do
@@ -137,18 +130,14 @@ describe PostReceive do
expect(project).to receive(:execute_hooks).twice
expect(project).to receive(:execute_services).twice
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
it "enqueues a UpdateMergeRequestsWorker job" do
allow(Project).to receive(:find_by).and_return(project)
expect(UpdateMergeRequestsWorker).to receive(:perform_async).with(project.id, project.owner.id, any_args)
- described_class.new.perform(project_identifier, key_id, base64_changes)
+ described_class.new.perform(gl_repository, key_id, base64_changes)
end
end
-
- def pwd(project)
- File.join(Gitlab.config.repositories.storages.default['path'], project.path_with_namespace)
- end
end
diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb
index 3d135f40c1f..f19c9dff941 100644
--- a/spec/workers/project_destroy_worker_spec.rb
+++ b/spec/workers/project_destroy_worker_spec.rb
@@ -1,24 +1,36 @@
require 'spec_helper'
describe ProjectDestroyWorker do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :repository, pending_delete: true) }
let(:path) { project.repository.path_to_repo }
subject { described_class.new }
- describe "#perform" do
- it "deletes the project" do
+ describe '#perform' do
+ it 'deletes the project' do
subject.perform(project.id, project.owner.id, {})
expect(Project.all).not_to include(project)
expect(Dir.exist?(path)).to be_falsey
end
- it "deletes the project but skips repo deletion" do
+ it 'deletes the project but skips repo deletion' do
subject.perform(project.id, project.owner.id, { "skip_repo" => true })
expect(Project.all).not_to include(project)
expect(Dir.exist?(path)).to be_truthy
end
+
+ it 'does not raise error when project could not be found' do
+ expect do
+ subject.perform(-1, project.owner.id, {})
+ end.not_to raise_error
+ end
+
+ it 'does not raise error when user could not be found' do
+ expect do
+ subject.perform(project.id, -1, {})
+ end.not_to raise_error
+ end
end
end
diff --git a/spec/workers/schedule_update_user_activity_worker_spec.rb b/spec/workers/schedule_update_user_activity_worker_spec.rb
index e583c3203aa..32c59381b01 100644
--- a/spec/workers/schedule_update_user_activity_worker_spec.rb
+++ b/spec/workers/schedule_update_user_activity_worker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ScheduleUpdateUserActivityWorker, :redis do
+describe ScheduleUpdateUserActivityWorker, :clean_gitlab_redis_shared_state do
let(:now) { Time.now }
before do
diff --git a/spec/workers/update_user_activity_worker_spec.rb b/spec/workers/update_user_activity_worker_spec.rb
index 43e9511f116..268ca1d81f2 100644
--- a/spec/workers/update_user_activity_worker_spec.rb
+++ b/spec/workers/update_user_activity_worker_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UpdateUserActivityWorker, :redis do
+describe UpdateUserActivityWorker, :clean_gitlab_redis_shared_state do
let(:user_active_2_days_ago) { create(:user, current_sign_in_at: 10.months.ago) }
let(:user_active_yesterday_1) { create(:user) }
let(:user_active_yesterday_2) { create(:user) }
@@ -25,7 +25,7 @@ describe UpdateUserActivityWorker, :redis do
end
end
- it 'deletes the pairs from Redis' do
+ it 'deletes the pairs from SharedState' do
data.each { |id, time| Gitlab::UserActivities.record(id, time) }
subject.perform(data)