summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorPawel Chojnacki <pawel@chojnacki.ws>2017-06-16 18:19:41 +0200
committerPawel Chojnacki <pawel@chojnacki.ws>2017-06-16 18:19:41 +0200
commit9f2c992ff1520e35d9b7bc26d603d597bc189618 (patch)
tree17af71363c63d99a15c76b1edcbceddc87bfc12d /spec
parent64bb0d37d4ef1f8574355019f198e40bc9b70224 (diff)
parent5f42009f8dcc29d559ee415e92c88858e361f063 (diff)
downloadgitlab-ce-9f2c992ff1520e35d9b7bc26d603d597bc189618.tar.gz
Merge remote-tracking branch 'upstream/master' into 28717-additional-metrics-review-branch
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/admin/identities_controller_spec.rb5
-rw-r--r--spec/controllers/admin/services_controller_spec.rb4
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb34
-rw-r--r--spec/controllers/dashboard/milestones_controller_spec.rb38
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb63
-rw-r--r--spec/controllers/health_controller_spec.rb39
-rw-r--r--spec/controllers/metrics_controller_spec.rb70
-rw-r--r--spec/controllers/notification_settings_controller_spec.rb23
-rw-r--r--spec/controllers/profiles/personal_access_tokens_controller_spec.rb8
-rw-r--r--spec/controllers/profiles_controller_spec.rb31
-rw-r--r--spec/controllers/projects/boards/lists_controller_spec.rb2
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb14
-rw-r--r--spec/controllers/projects/commit_controller_spec.rb8
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb12
-rw-r--r--spec/controllers/projects/forks_controller_spec.rb16
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb5
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb30
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb147
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb6
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb65
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb46
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb61
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb32
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb8
-rw-r--r--spec/controllers/projects_controller_spec.rb12
-rw-r--r--spec/controllers/search_controller_spec.rb4
-rw-r--r--spec/controllers/sent_notifications_controller_spec.rb25
-rw-r--r--spec/controllers/sessions_controller_spec.rb8
-rw-r--r--spec/controllers/snippets_controller_spec.rb44
-rw-r--r--spec/controllers/uploads_controller_spec.rb34
-rw-r--r--spec/controllers/users_controller_spec.rb8
-rw-r--r--spec/db/production/settings.rb16
-rw-r--r--spec/db/production/settings_spec.rb58
-rw-r--r--spec/factories/ci/builds.rb4
-rw-r--r--spec/factories/ci/stages.rb6
-rw-r--r--spec/factories/lists.rb6
-rw-r--r--spec/factories/snippets.rb1
-rw-r--r--spec/factories/uploads.rb8
-rw-r--r--spec/features/admin/admin_appearance_spec.rb4
-rw-r--r--spec/features/admin/admin_deploy_keys_spec.rb63
-rw-r--r--spec/features/admin/admin_groups_spec.rb4
-rw-r--r--spec/features/admin/admin_runners_spec.rb5
-rw-r--r--spec/features/admin/admin_settings_spec.rb5
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb4
-rw-r--r--spec/features/admin/admin_users_spec.rb9
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb4
-rw-r--r--spec/features/boards/boards_spec.rb174
-rw-r--r--spec/features/boards/issue_ordering_spec.rb36
-rw-r--r--spec/features/boards/new_issue_spec.rb20
-rw-r--r--spec/features/boards/sidebar_spec.rb8
-rw-r--r--spec/features/dashboard/groups_list_spec.rb122
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb4
-rw-r--r--spec/features/dashboard/milestone_tabs_spec.rb40
-rw-r--r--spec/features/dashboard/project_member_activity_index_spec.rb12
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb6
-rw-r--r--spec/features/explore/new_menu_spec.rb172
-rw-r--r--spec/features/groups/group_settings_spec.rb11
-rw-r--r--spec/features/groups_spec.rb8
-rw-r--r--spec/features/help_pages_spec.rb37
-rw-r--r--spec/features/issuables/default_sort_order_spec.rb8
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb8
-rw-r--r--spec/features/issues/form_spec.rb41
-rw-r--r--spec/features/issues/note_polling_spec.rb17
-rw-r--r--spec/features/issues_spec.rb5
-rw-r--r--spec/features/login_spec.rb12
-rw-r--r--spec/features/merge_requests/conflicts_spec.rb8
-rw-r--r--spec/features/merge_requests/created_from_fork_spec.rb2
-rw-r--r--spec/features/merge_requests/diff_notes_avatars_spec.rb4
-rw-r--r--spec/features/merge_requests/filter_merge_requests_spec.rb16
-rw-r--r--spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb4
-rw-r--r--spec/features/merge_requests/mini_pipeline_graph_spec.rb28
-rw-r--r--spec/features/merge_requests/pipelines_spec.rb2
-rw-r--r--spec/features/merge_requests/user_posts_notes_spec.rb8
-rw-r--r--spec/features/milestones/milestones_spec.rb10
-rw-r--r--spec/features/profiles/account_spec.rb9
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb6
-rw-r--r--spec/features/projects/artifacts/file_spec.rb1
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb40
-rw-r--r--spec/features/projects/blobs/edit_spec.rb6
-rw-r--r--spec/features/projects/blobs/user_create_spec.rb94
-rw-r--r--spec/features/projects/diffs/diff_show_spec.rb133
-rw-r--r--spec/features/projects/features_visibility_spec.rb5
-rw-r--r--spec/features/projects/group_links_spec.rb9
-rw-r--r--spec/features/projects/jobs_spec.rb241
-rw-r--r--spec/features/projects/new_project_spec.rb4
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb20
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb42
-rw-r--r--spec/features/projects/project_settings_spec.rb23
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb78
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb86
-rw-r--r--spec/features/projects/user_create_dir_spec.rb16
-rw-r--r--spec/features/projects/wiki/markdown_preview_spec.rb3
-rw-r--r--spec/features/protected_branches_spec.rb4
-rw-r--r--spec/features/protected_tags_spec.rb4
-rw-r--r--spec/features/reportable_note/commit_spec.rb33
-rw-r--r--spec/features/reportable_note/issue_spec.rb17
-rw-r--r--spec/features/reportable_note/merge_request_spec.rb26
-rw-r--r--spec/features/reportable_note/snippets_spec.rb33
-rw-r--r--spec/features/runners_spec.rb9
-rw-r--r--spec/features/search_spec.rb4
-rw-r--r--spec/features/security/project/internal_access_spec.rb16
-rw-r--r--spec/features/security/project/public_access_spec.rb16
-rw-r--r--spec/features/signup_spec.rb8
-rw-r--r--spec/features/snippets/create_snippet_spec.rb73
-rw-r--r--spec/features/snippets/edit_snippet_spec.rb38
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb12
-rw-r--r--spec/features/task_lists_spec.rb4
-rw-r--r--spec/features/todos/todos_sorting_spec.rb4
-rw-r--r--spec/features/todos/todos_spec.rb23
-rw-r--r--spec/features/triggers_spec.rb5
-rw-r--r--spec/features/u2f_spec.rb8
-rw-r--r--spec/features/unsubscribe_links_spec.rb4
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_group_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_avatar_to_profile_spec.rb2
-rw-r--r--spec/features/user_can_display_performance_bar_spec.rb81
-rw-r--r--spec/features/users_spec.rb4
-rw-r--r--spec/finders/issues_finder_spec.rb4
-rw-r--r--spec/finders/personal_access_tokens_finder_spec.rb84
-rw-r--r--spec/finders/personal_projects_finder_spec.rb4
-rw-r--r--spec/finders/pipelines_finder_spec.rb2
-rw-r--r--spec/finders/todos_finder_spec.rb4
-rw-r--r--spec/fixtures/api/schemas/list.json2
-rw-r--r--spec/helpers/application_helper_spec.rb33
-rw-r--r--spec/helpers/blame_helper_spec.rb59
-rw-r--r--spec/helpers/diff_helper_spec.rb39
-rw-r--r--spec/helpers/emails_helper_spec.rb2
-rw-r--r--spec/helpers/groups_helper_spec.rb2
-rw-r--r--spec/helpers/notes_helper_spec.rb10
-rw-r--r--spec/helpers/notifications_helper_spec.rb6
-rw-r--r--spec/helpers/page_layout_helper_spec.rb2
-rw-r--r--spec/helpers/profiles_helper_spec.rb36
-rw-r--r--spec/helpers/projects_helper_spec.rb37
-rw-r--r--spec/helpers/todos_helper_spec.rb13
-rw-r--r--spec/helpers/u2f_helper_spec.rb49
-rw-r--r--spec/initializers/8_metrics_spec.rb1
-rw-r--r--spec/javascripts/blob/create_branch_dropdown_spec.js106
-rw-r--r--spec/javascripts/blob/target_branch_dropdown_spec.js118
-rw-r--r--spec/javascripts/boards/components/board_spec.js112
-rw-r--r--spec/javascripts/bootstrap_linked_tabs_spec.js15
-rw-r--r--spec/javascripts/build_spec.js19
-rw-r--r--spec/javascripts/commits_spec.js13
-rw-r--r--spec/javascripts/datetime_utility_spec.js31
-rw-r--r--spec/javascripts/deploy_keys/components/key_spec.js18
-rw-r--r--spec/javascripts/filtered_search/filtered_search_manager_spec.js43
-rw-r--r--spec/javascripts/fixtures/boards.rb28
-rw-r--r--spec/javascripts/fixtures/project_branches.json5
-rw-r--r--spec/javascripts/fixtures/target_branch_dropdown.html.haml28
-rw-r--r--spec/javascripts/gl_dropdown_spec.js4
-rw-r--r--spec/javascripts/gl_emoji_spec.js31
-rw-r--r--spec/javascripts/groups/group_item_spec.js102
-rw-r--r--spec/javascripts/groups/groups_spec.js64
-rw-r--r--spec/javascripts/groups/mock_data.js114
-rw-r--r--spec/javascripts/issue_show/components/app_spec.js2
-rw-r--r--spec/javascripts/jobs/header_spec.js63
-rw-r--r--spec/javascripts/jobs/job_details_mediator_spec.js43
-rw-r--r--spec/javascripts/jobs/job_store_spec.js26
-rw-r--r--spec/javascripts/jobs/mock_data.js123
-rw-r--r--spec/javascripts/jobs/sidebar_detail_row_spec.js40
-rw-r--r--spec/javascripts/jobs/sidebar_details_block_spec.js111
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js8
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js25
-rw-r--r--spec/javascripts/notes_spec.js101
-rw-r--r--spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js2
-rw-r--r--spec/javascripts/pipelines/nav_controls_spec.js2
-rw-r--r--spec/javascripts/pipelines/pipeline_url_spec.js4
-rw-r--r--spec/javascripts/pipelines/pipelines_actions_spec.js2
-rw-r--r--spec/javascripts/pipelines/pipelines_artifacts_spec.js2
-rw-r--r--spec/javascripts/pipelines/pipelines_spec.js2
-rw-r--r--spec/javascripts/pipelines/time_ago_spec.js2
-rw-r--r--spec/javascripts/pipelines_spec.js5
-rw-r--r--spec/javascripts/test_bundle.js1
-rw-r--r--spec/javascripts/vue_shared/components/commit_spec.js6
-rw-r--r--spec/javascripts/vue_shared/components/header_ci_component_spec.js7
-rw-r--r--spec/javascripts/vue_shared/components/pipelines_table_row_spec.js20
-rw-r--r--spec/javascripts/vue_shared/components/pipelines_table_spec.js18
-rw-r--r--spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js13
-rw-r--r--spec/lib/banzai/filter/abstract_reference_filter_spec.rb11
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb8
-rw-r--r--spec/lib/banzai/issuable_extractor_spec.rb11
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/label_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/milestone_parser_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/snippet_parser_spec.rb189
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb11
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb329
-rw-r--r--spec/lib/extracts_path_spec.rb5
-rw-r--r--spec/lib/gitlab/auth/unique_ips_limiter_spec.rb4
-rw-r--r--spec/lib/gitlab/auth_spec.rb32
-rw-r--r--spec/lib/gitlab/background_migration_spec.rb48
-rw-r--r--spec/lib/gitlab/backup/repository_spec.rb63
-rw-r--r--spec/lib/gitlab/badge/build/status_spec.rb8
-rw-r--r--spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb4
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb61
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/environment_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/config/entry/image_spec.rb113
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/service_spec.rb119
-rw-r--r--spec/lib/gitlab/ci/config/entry/services_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/stage/seed_spec.rb57
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/play_spec.rb4
-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/status/external/common_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/common_spec.rb4
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb37
-rw-r--r--spec/lib/gitlab/database_spec.rb16
-rw-r--r--spec/lib/gitlab/diff/diff_refs_spec.rb61
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb12
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb329
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb48
-rw-r--r--spec/lib/gitlab/etag_caching/middleware_spec.rb52
-rw-r--r--spec/lib/gitlab/etag_caching/router_spec.rb44
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/git/compare_spec.rb4
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb81
-rw-r--r--spec/lib/gitlab/git_access_spec.rb68
-rw-r--r--spec/lib/gitlab/gitaly_client/notifications_spec.rb5
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_spec.rb15
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb24
-rw-r--r--spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb41
-rw-r--r--spec/lib/gitlab/highlight_spec.rb41
-rw-r--r--spec/lib/gitlab/i18n_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml7
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml11
-rw-r--r--spec/lib/gitlab/kubernetes_spec.rb10
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb16
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb30
-rw-r--r--spec/lib/gitlab/metrics_spec.rb145
-rw-r--r--spec/lib/gitlab/middleware/rails_queue_duration_spec.rb8
-rw-r--r--spec/lib/gitlab/o_auth/auth_hash_spec.rb12
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb128
-rw-r--r--spec/lib/gitlab/redis_spec.rb13
-rw-r--r--spec/lib/gitlab/saml/user_spec.rb62
-rw-r--r--spec/lib/gitlab/serializer/pagination_spec.rb4
-rw-r--r--spec/lib/gitlab/template/issue_template_spec.rb9
-rw-r--r--spec/lib/gitlab/template/merge_request_template_spec.rb9
-rw-r--r--spec/lib/gitlab/uploads_transfer_spec.rb11
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb11
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb2
-rw-r--r--spec/lib/json_web_token/rsa_token_spec.rb8
-rw-r--r--spec/lib/json_web_token/token_spec.rb5
-rw-r--r--spec/mailers/notify_spec.rb37
-rw-r--r--spec/migrations/README.md87
-rw-r--r--spec/migrations/clean_upload_symlinks_spec.rb46
-rw-r--r--spec/migrations/convert_custom_notification_settings_to_columns_spec.rb118
-rw-r--r--spec/migrations/migrate_build_stage_reference_spec.rb62
-rw-r--r--spec/migrations/migrate_pipeline_stages_spec.rb56
-rw-r--r--spec/migrations/move_uploads_to_system_dir_spec.rb68
-rw-r--r--spec/migrations/rename_more_reserved_project_names_spec.rb4
-rw-r--r--spec/migrations/rename_reserved_project_names_spec.rb4
-rw-r--r--spec/migrations/rename_system_namespaces_spec.rb254
-rw-r--r--spec/migrations/update_upload_paths_to_system_spec.rb53
-rw-r--r--spec/models/application_setting_spec.rb4
-rw-r--r--spec/models/blob_spec.rb8
-rw-r--r--spec/models/blob_viewer/base_spec.rb4
-rw-r--r--spec/models/broadcast_message_spec.rb19
-rw-r--r--spec/models/ci/build_spec.rb46
-rw-r--r--spec/models/ci/legacy_stage_spec.rb (renamed from spec/models/ci/stage_spec.rb)13
-rw-r--r--spec/models/ci/pipeline_spec.rb45
-rw-r--r--spec/models/commit_spec.rb40
-rw-r--r--spec/models/commit_status_spec.rb42
-rw-r--r--spec/models/concerns/access_requestable_spec.rb8
-rw-r--r--spec/models/concerns/issuable_spec.rb16
-rw-r--r--spec/models/concerns/mentionable_spec.rb4
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb23
-rw-r--r--spec/models/concerns/routable_spec.rb11
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb5
-rw-r--r--spec/models/deployment_spec.rb4
-rw-r--r--spec/models/diff_viewer/base_spec.rb150
-rw-r--r--spec/models/diff_viewer/server_side_spec.rb36
-rw-r--r--spec/models/environment_spec.rb2
-rw-r--r--spec/models/generic_commit_status_spec.rb9
-rw-r--r--spec/models/group_spec.rb29
-rw-r--r--spec/models/issue_spec.rb18
-rw-r--r--spec/models/merge_request_diff_spec.rb8
-rw-r--r--spec/models/merge_request_spec.rb16
-rw-r--r--spec/models/namespace_spec.rb10
-rw-r--r--spec/models/note_spec.rb8
-rw-r--r--spec/models/notification_setting_spec.rb30
-rw-r--r--spec/models/personal_access_token_spec.rb20
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb8
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb8
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb8
-rw-r--r--spec/models/project_services/campfire_service_spec.rb8
-rw-r--r--spec/models/project_services/chat_message/wiki_page_message_spec.rb40
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb8
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb8
-rw-r--r--spec/models/project_services/emails_on_push_service_spec.rb8
-rw-r--r--spec/models/project_services/external_wiki_service_spec.rb8
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb8
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb8
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb8
-rw-r--r--spec/models/project_services/irker_service_spec.rb8
-rw-r--r--spec/models/project_services/jira_service_spec.rb8
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb96
-rw-r--r--spec/models/project_services/microsoft_teams_service_spec.rb8
-rw-r--r--spec/models/project_services/pivotaltracker_service_spec.rb8
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb8
-rw-r--r--spec/models/project_services/pushover_service_spec.rb8
-rw-r--r--spec/models/project_services/redmine_service_spec.rb8
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb8
-rw-r--r--spec/models/project_spec.rb30
-rw-r--r--spec/models/project_team_spec.rb15
-rw-r--r--spec/models/project_wiki_spec.rb5
-rw-r--r--spec/models/repository_spec.rb40
-rw-r--r--spec/models/route_spec.rb9
-rw-r--r--spec/models/user_spec.rb18
-rw-r--r--spec/policies/ci/build_policy_spec.rb12
-rw-r--r--spec/policies/deploy_key_policy_spec.rb56
-rw-r--r--spec/policies/project_policy_spec.rb12
-rw-r--r--spec/policies/project_snippet_policy_spec.rb16
-rw-r--r--spec/presenters/merge_request_presenter_spec.rb10
-rw-r--r--spec/presenters/projects/settings/deploy_keys_presenter_spec.rb4
-rw-r--r--spec/requests/api/award_emoji_spec.rb4
-rw-r--r--spec/requests/api/commit_statuses_spec.rb53
-rw-r--r--spec/requests/api/commits_spec.rb12
-rw-r--r--spec/requests/api/deploy_keys_spec.rb77
-rw-r--r--spec/requests/api/files_spec.rb4
-rw-r--r--spec/requests/api/helpers_spec.rb38
-rw-r--r--spec/requests/api/internal_spec.rb40
-rw-r--r--spec/requests/api/jobs_spec.rb114
-rw-r--r--spec/requests/api/keys_spec.rb4
-rw-r--r--spec/requests/api/labels_spec.rb12
-rw-r--r--spec/requests/api/milestones_spec.rb4
-rw-r--r--spec/requests/api/notes_spec.rb12
-rw-r--r--spec/requests/api/pipelines_spec.rb12
-rw-r--r--spec/requests/api/project_snippets_spec.rb28
-rw-r--r--spec/requests/api/projects_spec.rb52
-rw-r--r--spec/requests/api/runner_spec.rb96
-rw-r--r--spec/requests/api/settings_spec.rb8
-rw-r--r--spec/requests/api/snippets_spec.rb27
-rw-r--r--spec/requests/api/system_hooks_spec.rb4
-rw-r--r--spec/requests/api/templates_spec.rb12
-rw-r--r--spec/requests/api/users_spec.rb47
-rw-r--r--spec/requests/ci/api/builds_spec.rb24
-rw-r--r--spec/requests/ci/api/runners_spec.rb9
-rw-r--r--spec/requests/git_http_spec.rb68
-rw-r--r--spec/requests/jwt_controller_spec.rb38
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/routing/project_routing_spec.rb12
-rw-r--r--spec/routing/routing_spec.rb4
-rw-r--r--spec/rubocop/cop/activerecord_serialize_spec.rb4
-rw-r--r--spec/rubocop/cop/migration/add_timestamps_spec.rb90
-rw-r--r--spec/rubocop/cop/migration/datetime_spec.rb90
-rw-r--r--spec/rubocop/cop/migration/timestamps_spec.rb99
-rw-r--r--spec/rubocop/cop/polymorphic_associations_spec.rb33
-rw-r--r--spec/rubocop/cop/rspec/single_line_hook_spec.rb66
-rw-r--r--spec/serializers/build_details_entity_spec.rb6
-rw-r--r--spec/serializers/deploy_key_entity_spec.rb61
-rw-r--r--spec/serializers/environment_serializer_spec.rb12
-rw-r--r--spec/serializers/job_entity_spec.rb (renamed from spec/serializers/build_entity_spec.rb)65
-rw-r--r--spec/serializers/pipeline_details_entity_spec.rb22
-rw-r--r--spec/serializers/pipeline_entity_spec.rb8
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb19
-rw-r--r--spec/serializers/stage_entity_spec.rb11
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb24
-rw-r--r--spec/services/boards/create_service_spec.rb5
-rw-r--r--spec/services/boards/issues/list_service_spec.rb11
-rw-r--r--spec/services/boards/lists/list_service_spec.rb31
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb11
-rw-r--r--spec/services/ci/retry_build_service_spec.rb18
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb8
-rw-r--r--spec/services/create_deployment_service_spec.rb4
-rw-r--r--spec/services/groups/create_service_spec.rb8
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb2
-rw-r--r--spec/services/issues/create_service_spec.rb4
-rw-r--r--spec/services/issues/move_service_spec.rb10
-rw-r--r--spec/services/issues/update_service_spec.rb43
-rw-r--r--spec/services/members/create_service_spec.rb4
-rw-r--r--spec/services/merge_requests/build_service_spec.rb4
-rw-r--r--spec/services/merge_requests/create_service_spec.rb4
-rw-r--r--spec/services/merge_requests/merge_request_diff_cache_service_spec.rb4
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb4
-rw-r--r--spec/services/merge_requests/update_service_spec.rb25
-rw-r--r--spec/services/notes/slash_commands_service_spec.rb4
-rw-r--r--spec/services/notification_service_spec.rb3
-rw-r--r--spec/services/pages_service_spec.rb12
-rw-r--r--spec/services/projects/create_service_spec.rb2
-rw-r--r--spec/services/projects/participants_service_spec.rb4
-rw-r--r--spec/services/projects/transfer_service_spec.rb12
-rw-r--r--spec/services/slash_commands/interpret_service_spec.rb12
-rw-r--r--spec/services/spam_service_spec.rb4
-rw-r--r--spec/services/system_note_service_spec.rb2
-rw-r--r--spec/spec_helper.rb26
-rw-r--r--spec/support/capybara.rb4
-rw-r--r--spec/support/db_cleaner.rb4
-rw-r--r--spec/support/features/reportable_note_shared_examples.rb36
-rw-r--r--spec/support/helpers/note_interaction_helpers.rb8
-rw-r--r--spec/support/javascript_fixtures_helpers.rb2
-rw-r--r--spec/support/kubernetes_helpers.rb33
-rw-r--r--spec/support/matchers/gitaly_matchers.rb9
-rw-r--r--spec/support/migrations_helpers.rb29
-rw-r--r--spec/support/milestone_tabs_examples.rb38
-rw-r--r--spec/support/reference_parser_shared_examples.rb8
-rw-r--r--spec/support/services/issuable_create_service_slash_commands_shared_examples.rb4
-rw-r--r--spec/support/services/issuable_update_service_shared_examples.rb4
-rw-r--r--spec/support/slack_mattermost_notifications_shared_examples.rb8
-rw-r--r--spec/support/target_branch_helpers.rb16
-rw-r--r--spec/support/unique_ip_check_shared_examples.rb8
-rw-r--r--spec/support/updating_mentions_shared_examples.rb12
-rw-r--r--spec/support/wait_for_requests.rb8
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb4
-rw-r--r--spec/tasks/gitlab/gitaly_rake_spec.rb11
-rw-r--r--spec/unicorn/unicorn_spec.rb4
-rw-r--r--spec/uploaders/artifact_uploader_spec.rb31
-rw-r--r--spec/uploaders/attachment_uploader_spec.rb11
-rw-r--r--spec/uploaders/avatar_uploader_spec.rb11
-rw-r--r--spec/uploaders/file_mover_spec.rb63
-rw-r--r--spec/uploaders/file_uploader_spec.rb10
-rw-r--r--spec/uploaders/gitlab_uploader_spec.rb15
-rw-r--r--spec/uploaders/lfs_object_uploader_spec.rb39
-rw-r--r--spec/uploaders/records_uploads_spec.rb9
-rw-r--r--spec/views/help/index.html.haml_spec.rb2
-rw-r--r--spec/views/projects/diffs/_viewer.html.haml_spec.rb71
-rw-r--r--spec/views/projects/jobs/show.html.haml_spec.rb79
-rw-r--r--spec/workers/background_migration_worker_spec.rb13
-rw-r--r--spec/workers/emails_on_push_worker_spec.rb4
-rw-r--r--spec/workers/expire_build_artifacts_worker_spec.rb8
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb4
-rw-r--r--spec/workers/post_receive_spec.rb33
-rw-r--r--spec/workers/stuck_ci_jobs_worker_spec.rb12
433 files changed, 9536 insertions, 2461 deletions
diff --git a/spec/controllers/admin/identities_controller_spec.rb b/spec/controllers/admin/identities_controller_spec.rb
index c131d22a30a..a29853bf8df 100644
--- a/spec/controllers/admin/identities_controller_spec.rb
+++ b/spec/controllers/admin/identities_controller_spec.rb
@@ -2,7 +2,10 @@ require 'spec_helper'
describe Admin::IdentitiesController do
let(:admin) { create(:admin) }
- before { sign_in(admin) }
+
+ before do
+ sign_in(admin)
+ end
describe 'UPDATE identity' do
let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') }
diff --git a/spec/controllers/admin/services_controller_spec.rb b/spec/controllers/admin/services_controller_spec.rb
index c94616d8508..4ca0cfc74e9 100644
--- a/spec/controllers/admin/services_controller_spec.rb
+++ b/spec/controllers/admin/services_controller_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
describe Admin::ServicesController do
let(:admin) { create(:admin) }
- before { sign_in(admin) }
+ before do
+ sign_in(admin)
+ end
describe 'GET #edit' do
let!(:project) { create(:empty_project) }
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index 2c9d1ffc9c2..b40f647644d 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -170,27 +170,39 @@ describe AutocompleteController do
end
context 'author of issuable included' do
- before do
- sign_in(user)
- end
-
let(:body) { JSON.parse(response.body) }
- it 'includes the author' do
- get(:users, author_id: non_member.id)
+ context 'authenticated' do
+ before do
+ sign_in(user)
+ end
- expect(body.first["username"]).to eq non_member.username
+ it 'includes the author' do
+ get(:users, author_id: non_member.id)
+
+ expect(body.first["username"]).to eq non_member.username
+ end
+
+ it 'rejects non existent user ids' do
+ get(:users, author_id: 99999)
+
+ expect(body.collect { |u| u['id'] }).not_to include(99999)
+ end
end
- it 'rejects non existent user ids' do
- get(:users, author_id: 99999)
+ context 'without authenticating' do
+ it 'returns empty result' do
+ get(:users, author_id: non_member.id)
- expect(body.collect { |u| u['id'] }).not_to include(99999)
+ expect(body).to be_empty
+ end
end
end
context 'skip_users parameter included' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'skips the user IDs passed' do
get(:users, skip_users: [user, user2].map(&:id))
diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb
new file mode 100644
index 00000000000..424f39fd3b8
--- /dev/null
+++ b/spec/controllers/dashboard/milestones_controller_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Dashboard::MilestonesController do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let(:project_milestone) { create(:milestone, project: project) }
+ let(:milestone) do
+ DashboardMilestone.build(
+ [project],
+ project_milestone.title
+ )
+ end
+ let(:issue) { create(:issue, project: project, milestone: project_milestone) }
+ let!(:label) { create(:label, project: project, title: 'Issue Label', issues: [issue]) }
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: project_milestone) }
+ let(:milestone_path) { dashboard_milestone_path(milestone.safe_title, title: milestone.title) }
+
+ before do
+ sign_in(user)
+ project.team << [user, :master]
+ end
+
+ it_behaves_like 'milestone tabs'
+
+ describe "#show" do
+ render_views
+
+ def view_milestone
+ get :show, id: milestone.safe_title, title: milestone.title
+ end
+
+ it 'shows milestone page' do
+ view_milestone
+
+ expect(response).to have_http_status(200)
+ end
+ end
+end
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index 60db0192dfd..cce53f6697c 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -16,10 +16,14 @@ describe Groups::GroupMembersController do
describe 'POST create' do
let(:group_user) { create(:user) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when user does not have enough rights' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'returns 403' do
post :create, group_id: group,
@@ -32,7 +36,9 @@ describe Groups::GroupMembersController do
end
context 'when user has enough rights' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it 'adds user to members' do
post :create, group_id: group,
@@ -59,7 +65,9 @@ describe Groups::GroupMembersController do
describe 'DELETE destroy' do
let(:member) { create(:group_member, :developer, group: group) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 403' do
@@ -71,7 +79,9 @@ describe Groups::GroupMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'returns 403' do
delete :destroy, group_id: group, id: member
@@ -82,7 +92,9 @@ describe Groups::GroupMembersController do
end
context 'when user has enough rights' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it '[HTML] removes user from members' do
delete :destroy, group_id: group, id: member
@@ -103,7 +115,9 @@ describe Groups::GroupMembersController do
end
describe 'DELETE leave' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -115,7 +129,9 @@ describe Groups::GroupMembersController do
context 'when member is found' do
context 'and is not an owner' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'removes user from members' do
delete :leave, group_id: group
@@ -124,10 +140,19 @@ describe Groups::GroupMembersController do
expect(response).to redirect_to(dashboard_groups_path)
expect(group.users).not_to include user
end
+
+ it 'supports json request' do
+ delete :leave, group_id: group, format: :json
+
+ expect(response).to have_http_status(200)
+ expect(json_response['notice']).to eq "You left the \"#{group.name}\" group."
+ end
end
context 'and is an owner' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it 'cannot removes himself from the group' do
delete :leave, group_id: group
@@ -137,7 +162,9 @@ describe Groups::GroupMembersController do
end
context 'and is a requester' do
- before { group.request_access(user) }
+ before do
+ group.request_access(user)
+ end
it 'removes user from members' do
delete :leave, group_id: group
@@ -152,7 +179,9 @@ describe Groups::GroupMembersController do
end
describe 'POST request_access' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'creates a new GroupMember that is not a team member' do
post :request_access, group_id: group
@@ -167,7 +196,9 @@ describe Groups::GroupMembersController do
describe 'POST approve_access_request' do
let(:member) { create(:group_member, :access_request, group: group) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 403' do
@@ -179,7 +210,9 @@ describe Groups::GroupMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
it 'returns 403' do
post :approve_access_request, group_id: group, id: member
@@ -190,7 +223,9 @@ describe Groups::GroupMembersController do
end
context 'when user has enough rights' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it 'adds user to members' do
post :approve_access_request, group_id: group, id: member
diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb
index b8b6e0c3a88..e7c19b47a6a 100644
--- a/spec/controllers/health_controller_spec.rb
+++ b/spec/controllers/health_controller_spec.rb
@@ -54,43 +54,4 @@ describe HealthController do
end
end
end
-
- describe '#metrics' do
- context 'authorization token provided' do
- before do
- request.headers['TOKEN'] = token
- end
-
- it 'returns DB ping metrics' do
- get :metrics
- 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\.]+$/)
- end
-
- it 'returns Redis ping metrics' do
- get :metrics
- 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\.]+$/)
- end
-
- it 'returns file system check metrics' do
- get :metrics
- expect(response.body).to match(/^filesystem_access_latency{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_writable{shard="default"} 1$/)
- expect(response.body).to match(/^filesystem_read_latency{shard="default"} [0-9\.]+$/)
- expect(response.body).to match(/^filesystem_readable{shard="default"} 1$/)
- end
- end
-
- context 'without authorization token' do
- it 'returns proper response' do
- get :metrics
- expect(response.status).to eq(404)
- end
- end
- end
end
diff --git a/spec/controllers/metrics_controller_spec.rb b/spec/controllers/metrics_controller_spec.rb
new file mode 100644
index 00000000000..044c9f179ed
--- /dev/null
+++ b/spec/controllers/metrics_controller_spec.rb
@@ -0,0 +1,70 @@
+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 }
+
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ stub_env('prometheus_multiproc_dir', metrics_multiproc_dir)
+ allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(true)
+ end
+
+ describe '#index' do
+ context 'authorization token provided' do
+ before do
+ request.headers['TOKEN'] = token
+ end
+
+ 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\.]+$/)
+ end
+
+ it 'returns Redis ping metrics' do
+ get :index
+
+ 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\.]+$/)
+ 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_accessible{shard="default"} 1$/)
+ expect(response.body).to match(/^filesystem_write_latency{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_readable{shard="default"} 1$/)
+ end
+
+ context 'prometheus metrics are disabled' do
+ before do
+ allow(Gitlab::Metrics).to receive(:prometheus_metrics_enabled?).and_return(false)
+ end
+
+ it 'returns proper response' do
+ get :index
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
+ context 'without authorization token' do
+ it 'returns proper response' do
+ get :index
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb
index 9e3a31e1a6b..6b690407ce3 100644
--- a/spec/controllers/notification_settings_controller_spec.rb
+++ b/spec/controllers/notification_settings_controller_spec.rb
@@ -58,7 +58,10 @@ describe NotificationSettingsController do
expect(response.status).to eq 200
expect(notification_setting.level).to eq("custom")
- expect(notification_setting.events).to eq(custom_events)
+
+ custom_events.each do |event, value|
+ expect(notification_setting.event_enabled?(event)).to eq(value)
+ end
end
end
end
@@ -86,7 +89,10 @@ describe NotificationSettingsController do
expect(response.status).to eq 200
expect(notification_setting.level).to eq("custom")
- expect(notification_setting.events).to eq(custom_events)
+
+ custom_events.each do |event, value|
+ expect(notification_setting.event_enabled?(event)).to eq(value)
+ end
end
end
end
@@ -94,7 +100,10 @@ describe NotificationSettingsController do
context 'not authorized' do
let(:private_project) { create(:empty_project, :private) }
- before { sign_in(user) }
+
+ before do
+ sign_in(user)
+ end
it 'returns 404' do
post :create,
@@ -120,7 +129,9 @@ describe NotificationSettingsController do
end
context 'when authorized' do
- before{ sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'returns success' do
put :update,
@@ -152,7 +163,9 @@ describe NotificationSettingsController do
context 'not authorized' do
let(:other_user) { create(:user) }
- before { sign_in(other_user) }
+ before do
+ sign_in(other_user)
+ end
it 'returns 404' do
put :update,
diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
index 98a43e278b2..ed08a4c1bf2 100644
--- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
+++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
@@ -4,7 +4,9 @@ describe Profiles::PersonalAccessTokensController do
let(:user) { create(:user) }
let(:token_attributes) { attributes_for(:personal_access_token) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
describe '#create' do
def created_token
@@ -38,7 +40,9 @@ describe Profiles::PersonalAccessTokensController do
let!(:inactive_personal_access_token) { create(:personal_access_token, :revoked, user: user) }
let!(:impersonation_personal_access_token) { create(:personal_access_token, :impersonation, user: user) }
- before { get :index }
+ before do
+ get :index
+ end
it "retrieves active personal access tokens" do
expect(assigns(:active_personal_access_tokens)).to include(active_personal_access_token)
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
new file mode 100644
index 00000000000..9d60dab12d1
--- /dev/null
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -0,0 +1,31 @@
+require('spec_helper')
+
+describe ProfilesController do
+ describe "PUT update" do
+ it "allows an email update from a user without an external email address" do
+ user = create(:user)
+ sign_in(user)
+
+ put :update,
+ user: { email: "john@gmail.com", name: "John" }
+
+ user.reload
+
+ expect(response.status).to eq(302)
+ expect(user.unconfirmed_email).to eq('john@gmail.com')
+ end
+
+ it "ignores an email update from a user with an external email address" do
+ ldap_user = create(:omniauth_user, external_email: true)
+ sign_in(ldap_user)
+
+ put :update,
+ user: { email: "john@gmail.com", name: "John" }
+
+ ldap_user.reload
+
+ expect(response.status).to eq(302)
+ expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com')
+ end
+ end
+end
diff --git a/spec/controllers/projects/boards/lists_controller_spec.rb b/spec/controllers/projects/boards/lists_controller_spec.rb
index 432f3c53c90..0f2664262e8 100644
--- a/spec/controllers/projects/boards/lists_controller_spec.rb
+++ b/spec/controllers/projects/boards/lists_controller_spec.rb
@@ -27,7 +27,7 @@ describe Projects::Boards::ListsController do
parsed_response = JSON.parse(response.body)
expect(response).to match_response_schema('lists')
- expect(parsed_response.length).to eq 2
+ expect(parsed_response.length).to eq 3
end
context 'with unauthorized user' do
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index f285e5333d6..f9e21f9d8f6 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -367,19 +367,5 @@ describe Projects::BranchesController do
expect(parsed_response.first).to eq 'master'
end
end
-
- context 'show_all = true' do
- it 'returns all the branches name' do
- get :index,
- namespace_id: project.namespace,
- project_id: project,
- format: :json,
- show_all: true
-
- parsed_response = JSON.parse(response.body)
-
- expect(parsed_response.length).to eq(project.repository.branches.count)
- end
- end
end
end
diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb
index 69e4706dc71..7fb08df1950 100644
--- a/spec/controllers/projects/commit_controller_spec.rb
+++ b/spec/controllers/projects/commit_controller_spec.rb
@@ -281,7 +281,9 @@ describe Projects::CommitController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ) }
+ before do
+ diff_for_path(id: commit.id, old_path: existing_path.succ, new_path: existing_path.succ)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -302,7 +304,9 @@ describe Projects::CommitController do
end
context 'when the commit does not exist' do
- before { diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(id: commit.id.succ, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 15ac4e0925a..8f4694c9854 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -128,7 +128,9 @@ describe Projects::CompareController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ) }
+ before do
+ diff_for_path(from: ref_from, to: ref_to, old_path: existing_path.succ, new_path: existing_path.succ)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -149,7 +151,9 @@ describe Projects::CompareController do
end
context 'when the from ref does not exist' do
- before { diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(from: ref_from.succ, to: ref_to, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
@@ -157,7 +161,9 @@ describe Projects::CompareController do
end
context 'when the to ref does not exist' do
- before { diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path) }
+ before do
+ diff_for_path(from: ref_from, to: ref_to.succ, old_path: existing_path, new_path: existing_path)
+ end
it 'returns a 404' do
expect(response).to have_http_status(404)
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb
index 8282d79298f..dc8290c438e 100644
--- a/spec/controllers/projects/forks_controller_spec.rb
+++ b/spec/controllers/projects/forks_controller_spec.rb
@@ -14,7 +14,9 @@ describe Projects::ForksController do
end
context 'when fork is public' do
- before { forked_project.update_attribute(:visibility_level, Project::PUBLIC) }
+ before do
+ forked_project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
it 'is visible for non logged in users' do
get_forks
@@ -35,7 +37,9 @@ describe Projects::ForksController do
end
context 'when user is logged in' do
- before { sign_in(project.creator) }
+ before do
+ sign_in(project.creator)
+ end
context 'when user is not a Project member neither a group member' do
it 'does not see the Project listed' do
@@ -46,7 +50,9 @@ describe Projects::ForksController do
end
context 'when user is a member of the Project' do
- before { forked_project.team << [project.creator, :developer] }
+ before do
+ forked_project.team << [project.creator, :developer]
+ end
it 'sees the project listed' do
get_forks
@@ -56,7 +62,9 @@ describe Projects::ForksController do
end
context 'when user is a member of the Group' do
- before { forked_project.group.add_developer(project.creator) }
+ before do
+ forked_project.group.add_developer(project.creator)
+ end
it 'sees the project listed' do
get_forks
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index ca4a8e871c0..b5435357f53 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -22,7 +22,10 @@ describe Projects::GroupLinksController do
end
context 'when user has access to group he want to link project to' do
- before { group.add_developer(user) }
+ before do
+ group.add_developer(user)
+ end
+
include_context 'link project to group'
it 'links project with selected group' do
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index a38ae2eb990..f853bfe370c 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -212,7 +212,9 @@ describe Projects::IssuesController do
let(:another_project) { create(:empty_project, :private) }
context 'when user has access to move issue' do
- before { another_project.team << [user, :reporter] }
+ before do
+ another_project.team << [user, :reporter]
+ end
it 'moves issue to another project' do
move_issue
@@ -250,16 +252,21 @@ describe Projects::IssuesController do
end
context 'when an issue is identified as spam' do
- before { allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) }
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
context 'when captcha is not verified' do
def update_spam_issue
update_issue(title: 'Spam Title', description: 'Spam lives here')
end
- before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) }
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
+ end
it 'rejects an issue recognized as a spam' do
+ expect(Gitlab::Recaptcha).to receive(:load_configurations!).and_return(true)
expect { update_spam_issue }.not_to change{ issue.reload.title }
end
@@ -619,14 +626,18 @@ describe Projects::IssuesController do
end
context 'when an issue is identified as spam' do
- before { allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true) }
+ before do
+ allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
+ end
context 'when captcha is not verified' do
def post_spam_issue
post_new_issue(title: 'Spam Title', description: 'Spam lives here')
end
- before { allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) }
+ before do
+ allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
+ end
it 'rejects an issue recognized as a spam' do
expect { post_spam_issue }.not_to change(Issue, :count)
@@ -738,7 +749,10 @@ describe Projects::IssuesController do
describe "DELETE #destroy" do
context "when the user is a developer" do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
+
it "rejects a developer to destroy an issue" do
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
expect(response).to have_http_status(404)
@@ -750,7 +764,9 @@ describe Projects::IssuesController do
let(:namespace) { create(:namespace, owner: owner) }
let(:project) { create(:empty_project, namespace: namespace) }
- before { sign_in(owner) }
+ before do
+ sign_in(owner)
+ end
it "deletes the issue" do
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 7211acc53dc..472e5fc51a0 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -28,7 +28,7 @@ describe Projects::JobsController do
get_index(scope: 'running')
end
- it 'has only running builds' do
+ it 'has only running jobs' do
expect(response).to have_http_status(:ok)
expect(assigns(:builds).first.status).to eq('running')
end
@@ -41,7 +41,7 @@ describe Projects::JobsController do
get_index(scope: 'finished')
end
- it 'has only finished builds' do
+ it 'has only finished jobs' do
expect(response).to have_http_status(:ok)
expect(assigns(:builds).first.status).to eq('success')
end
@@ -67,23 +67,16 @@ describe Projects::JobsController do
context 'number of queries' do
before do
Ci::Build::AVAILABLE_STATUSES.each do |status|
- create_build(status, status)
+ create_job(status, status)
end
-
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
end
- it "verifies number of queries" do
+ it 'verifies number of queries', :request_store do
recorded = ActiveRecord::QueryRecorder.new { get_index }
- expect(recorded.count).to be_within(5).of(8)
+ expect(recorded.count).to be_within(5).of(7)
end
- def create_build(name, status)
+ def create_job(name, status)
pipeline = create(:ci_pipeline, project: project)
create(:ci_build, :tags, :triggered, :artifacts,
pipeline: pipeline, name: name, status: status)
@@ -101,21 +94,21 @@ describe Projects::JobsController do
end
describe 'GET show' do
- let!(:build) { create(:ci_build, :failed, pipeline: pipeline) }
+ let!(:job) { create(:ci_build, :failed, pipeline: pipeline) }
context 'when requesting HTML' do
- context 'when build exists' do
+ context 'when job exists' do
before do
- get_show(id: build.id)
+ get_show(id: job.id)
end
- it 'has a build' do
+ it 'has a job' do
expect(response).to have_http_status(:ok)
- expect(assigns(:build).id).to eq(build.id)
+ expect(assigns(:build).id).to eq(job.id)
end
end
- context 'when build does not exist' do
+ context 'when job does not exist' do
before do
get_show(id: 1234)
end
@@ -135,12 +128,12 @@ describe Projects::JobsController do
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
- get_show(id: build.id, format: :json)
+ get_show(id: job.id, format: :json)
end
it 'exposes needed information' do
expect(response).to have_http_status(:ok)
- expect(json_response['raw_path']).to match(/builds\/\d+\/raw\z/)
+ expect(json_response['raw_path']).to match(/jobs\/\d+\/raw\z/)
expect(json_response.dig('merge_request', 'path')).to match(/merge_requests\/\d+\z/)
expect(json_response['new_issue_path'])
.to include('/issues/new')
@@ -162,35 +155,35 @@ describe Projects::JobsController do
get_trace
end
- context 'when build has a trace' do
- let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
+ context 'when job has a trace' do
+ let(:job) { create(:ci_build, :trace, pipeline: pipeline) }
it 'returns a trace' do
expect(response).to have_http_status(:ok)
- expect(json_response['id']).to eq build.id
- expect(json_response['status']).to eq build.status
+ expect(json_response['id']).to eq job.id
+ expect(json_response['status']).to eq job.status
expect(json_response['html']).to eq('BUILD TRACE')
end
end
- context 'when build has no traces' do
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ context 'when job has no traces' do
+ let(:job) { create(:ci_build, pipeline: pipeline) }
it 'returns no traces' do
expect(response).to have_http_status(:ok)
- expect(json_response['id']).to eq build.id
- expect(json_response['status']).to eq build.status
+ expect(json_response['id']).to eq job.id
+ expect(json_response['status']).to eq job.status
expect(json_response['html']).to be_nil
end
end
- context 'when build has a trace with ANSI sequence and Unicode' do
- let(:build) { create(:ci_build, :unicode_trace, pipeline: pipeline) }
+ context 'when job has a trace with ANSI sequence and Unicode' do
+ let(:job) { create(:ci_build, :unicode_trace, pipeline: pipeline) }
it 'returns a trace with Unicode' do
expect(response).to have_http_status(:ok)
- expect(json_response['id']).to eq build.id
- expect(json_response['status']).to eq build.status
+ expect(json_response['id']).to eq job.id
+ expect(json_response['status']).to eq job.status
expect(json_response['html']).to include("ヾ(´༎ຶД༎ຶ`)ノ")
end
end
@@ -198,23 +191,23 @@ describe Projects::JobsController do
def get_trace
get :trace, namespace_id: project.namespace,
project_id: project,
- id: build.id,
+ id: job.id,
format: :json
end
end
describe 'GET status.json' do
- let(:build) { create(:ci_build, pipeline: pipeline) }
- let(:status) { build.detailed_status(double('user')) }
+ let(:job) { create(:ci_build, pipeline: pipeline) }
+ let(:status) { job.detailed_status(double('user')) }
before do
get :status, namespace_id: project.namespace,
project_id: project,
- id: build.id,
+ id: job.id,
format: :json
end
- it 'return a detailed build status in json' do
+ it 'return a detailed job status in json' do
expect(response).to have_http_status(:ok)
expect(json_response['text']).to eq status.text
expect(json_response['label']).to eq status.label
@@ -231,17 +224,17 @@ describe Projects::JobsController do
post_retry
end
- context 'when build is retryable' do
- let(:build) { create(:ci_build, :retryable, pipeline: pipeline) }
+ context 'when job is retryable' do
+ let(:job) { create(:ci_build, :retryable, pipeline: pipeline) }
- it 'redirects to the retried build page' do
+ it 'redirects to the retried job page' do
expect(response).to have_http_status(:found)
expect(response).to redirect_to(namespace_project_job_path(id: Ci::Build.last.id))
end
end
- context 'when build is not retryable' do
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ context 'when job is not retryable' do
+ let(:job) { create(:ci_build, pipeline: pipeline) }
it 'renders unprocessable_entity' do
expect(response).to have_http_status(:unprocessable_entity)
@@ -251,7 +244,7 @@ describe Projects::JobsController do
def post_retry
post :retry, namespace_id: project.namespace,
project_id: project,
- id: build.id
+ id: job.id
end
end
@@ -267,21 +260,21 @@ describe Projects::JobsController do
post_play
end
- context 'when build is playable' do
- let(:build) { create(:ci_build, :playable, pipeline: pipeline) }
+ context 'when job is playable' do
+ let(:job) { create(:ci_build, :playable, pipeline: pipeline) }
- it 'redirects to the played build page' do
+ it 'redirects to the played job page' do
expect(response).to have_http_status(:found)
- expect(response).to redirect_to(namespace_project_job_path(id: build.id))
+ expect(response).to redirect_to(namespace_project_job_path(id: job.id))
end
it 'transits to pending' do
- expect(build.reload).to be_pending
+ expect(job.reload).to be_pending
end
end
- context 'when build is not playable' do
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ context 'when job is not playable' do
+ let(:job) { create(:ci_build, pipeline: pipeline) }
it 'renders unprocessable_entity' do
expect(response).to have_http_status(:unprocessable_entity)
@@ -291,7 +284,7 @@ describe Projects::JobsController do
def post_play
post :play, namespace_id: project.namespace,
project_id: project,
- id: build.id
+ id: job.id
end
end
@@ -303,21 +296,21 @@ describe Projects::JobsController do
post_cancel
end
- context 'when build is cancelable' do
- let(:build) { create(:ci_build, :cancelable, pipeline: pipeline) }
+ context 'when job is cancelable' do
+ let(:job) { create(:ci_build, :cancelable, pipeline: pipeline) }
- it 'redirects to the canceled build page' do
+ it 'redirects to the canceled job page' do
expect(response).to have_http_status(:found)
- expect(response).to redirect_to(namespace_project_job_path(id: build.id))
+ expect(response).to redirect_to(namespace_project_job_path(id: job.id))
end
it 'transits to canceled' do
- expect(build.reload).to be_canceled
+ expect(job.reload).to be_canceled
end
end
- context 'when build is not cancelable' do
- let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
+ context 'when job is not cancelable' do
+ let(:job) { create(:ci_build, :canceled, pipeline: pipeline) }
it 'returns unprocessable_entity' do
expect(response).to have_http_status(:unprocessable_entity)
@@ -327,7 +320,7 @@ describe Projects::JobsController do
def post_cancel
post :cancel, namespace_id: project.namespace,
project_id: project,
- id: build.id
+ id: job.id
end
end
@@ -337,7 +330,7 @@ describe Projects::JobsController do
sign_in(user)
end
- context 'when builds are cancelable' do
+ context 'when jobs are cancelable' do
before do
create_list(:ci_build, 2, :cancelable, pipeline: pipeline)
@@ -354,7 +347,7 @@ describe Projects::JobsController do
end
end
- context 'when builds are not cancelable' do
+ context 'when jobs are not cancelable' do
before do
create_list(:ci_build, 2, :canceled, pipeline: pipeline)
@@ -381,26 +374,26 @@ describe Projects::JobsController do
post_erase
end
- context 'when build is erasable' do
- let(:build) { create(:ci_build, :erasable, :trace, pipeline: pipeline) }
+ context 'when job is erasable' do
+ let(:job) { create(:ci_build, :erasable, :trace, pipeline: pipeline) }
- it 'redirects to the erased build page' do
+ it 'redirects to the erased job page' do
expect(response).to have_http_status(:found)
- expect(response).to redirect_to(namespace_project_job_path(id: build.id))
+ expect(response).to redirect_to(namespace_project_job_path(id: job.id))
end
it 'erases artifacts' do
- expect(build.artifacts_file.exists?).to be_falsey
- expect(build.artifacts_metadata.exists?).to be_falsey
+ expect(job.artifacts_file.exists?).to be_falsey
+ expect(job.artifacts_metadata.exists?).to be_falsey
end
it 'erases trace' do
- expect(build.trace.exist?).to be_falsey
+ expect(job.trace.exist?).to be_falsey
end
end
- context 'when build is not erasable' do
- let(:build) { create(:ci_build, :erased, pipeline: pipeline) }
+ context 'when job is not erasable' do
+ let(:job) { create(:ci_build, :erased, pipeline: pipeline) }
it 'returns unprocessable_entity' do
expect(response).to have_http_status(:unprocessable_entity)
@@ -410,7 +403,7 @@ describe Projects::JobsController do
def post_erase
post :erase, namespace_id: project.namespace,
project_id: project,
- id: build.id
+ id: job.id
end
end
@@ -419,8 +412,8 @@ describe Projects::JobsController do
get_raw
end
- context 'when build has a trace file' do
- let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
+ context 'when job has a trace file' do
+ let(:job) { create(:ci_build, :trace, pipeline: pipeline) }
it 'send a trace file' do
expect(response).to have_http_status(:ok)
@@ -429,8 +422,8 @@ describe Projects::JobsController do
end
end
- context 'when build does not have a trace file' do
- let(:build) { create(:ci_build, pipeline: pipeline) }
+ context 'when job does not have a trace file' do
+ let(:job) { create(:ci_build, pipeline: pipeline) }
it 'returns not_found' do
expect(response).to have_http_status(:not_found)
@@ -440,7 +433,7 @@ describe Projects::JobsController do
def get_raw
post :raw, namespace_id: project.namespace,
project_id: project,
- id: build.id
+ id: job.id
end
end
end
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index 130b0b744b5..bf1776eb320 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -117,7 +117,7 @@ describe Projects::LabelsController do
let!(:promoted_label_name) { "Promoted Label" }
let!(:label_1) { create(:label, title: promoted_label_name, project: project) }
- context 'not group owner' do
+ context 'not group reporters' do
it 'denies access' do
post :promote, namespace_id: project.namespace.to_param, project_id: project, id: label_1.to_param
@@ -125,9 +125,9 @@ describe Projects::LabelsController do
end
end
- context 'group owner' do
+ context 'group reporter' do
before do
- GroupMember.add_users(group, [user], :owner)
+ group.add_reporter(user)
end
it 'gives access' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 08024a2148b..d8a3a510f97 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -19,7 +19,10 @@ describe Projects::MergeRequestsController do
render_views
let(:fork_project) { create(:forked_project_with_submodules) }
- before { fork_project.team << [user, :master] }
+
+ before do
+ fork_project.team << [user, :master]
+ end
context 'when rendering HTML response' do
it 'renders new merge request widget template' do
@@ -119,14 +122,14 @@ describe Projects::MergeRequestsController do
end
end
- context 'number of queries' do
+ context 'number of queries', :request_store do
it 'verifies number of queries' do
# pre-create objects
merge_request
recorded = ActiveRecord::QueryRecorder.new { go(format: :json) }
- expect(recorded.count).to be_within(5).of(50)
+ expect(recorded.count).to be_within(5).of(30)
expect(recorded.cached_count).to eq(0)
end
end
@@ -328,7 +331,9 @@ describe Projects::MergeRequestsController do
end
context 'when the sha parameter does not match the source SHA' do
- before { post :merge, base_params.merge(sha: 'foo') }
+ before do
+ post :merge, base_params.merge(sha: 'foo')
+ end
it 'returns :sha_mismatch' do
expect(json_response).to eq('status' => 'sha_mismatch')
@@ -473,7 +478,9 @@ describe Projects::MergeRequestsController do
let(:namespace) { create(:namespace, owner: owner) }
let(:project) { create(:project, namespace: namespace) }
- before { sign_in owner }
+ before do
+ sign_in owner
+ end
it "deletes the merge request" do
delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid
@@ -505,7 +512,9 @@ describe Projects::MergeRequestsController do
context 'with default params' do
context 'as html' do
- before { go(format: 'html') }
+ before do
+ go(format: 'html')
+ end
it 'renders the diff template' do
expect(response).to render_template('diffs')
@@ -513,7 +522,9 @@ describe Projects::MergeRequestsController do
end
context 'as json' do
- before { go(format: 'json') }
+ 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')
@@ -544,7 +555,9 @@ describe Projects::MergeRequestsController do
context 'with ignore_whitespace_change' do
context 'as html' do
- before { go(format: 'html', w: 1) }
+ before do
+ go(format: 'html', w: 1)
+ end
it 'renders the diff template' do
expect(response).to render_template('diffs')
@@ -552,7 +565,9 @@ describe Projects::MergeRequestsController do
end
context 'as json' do
- before { go(format: 'json', w: 1) }
+ 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')
@@ -562,7 +577,9 @@ describe Projects::MergeRequestsController do
end
context 'with view' do
- before { go(view: 'parallel') }
+ before do
+ go(view: 'parallel')
+ end
it 'saves the preferred diff view in a cookie' do
expect(response.cookies['diff_view']).to eq('parallel')
@@ -605,7 +622,9 @@ describe Projects::MergeRequestsController do
end
context 'when the path does not exist in the diff' do
- before { diff_for_path(id: merge_request.iid, old_path: 'files/ruby/nopen.rb', new_path: 'files/ruby/nopen.rb') }
+ 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)
@@ -626,7 +645,9 @@ describe Projects::MergeRequestsController do
end
context 'when the merge request does not exist' do
- before { diff_for_path(id: merge_request.iid.succ, old_path: existing_path, new_path: existing_path) }
+ 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)
@@ -670,7 +691,9 @@ describe Projects::MergeRequestsController do
context 'when the source branch is in a different project to the target' do
let(:other_project) { create(:project) }
- before { other_project.team << [user, :master] }
+ before do
+ other_project.team << [user, :master]
+ end
context 'when the path exists in the diff' do
it 'disables diff notes' do
@@ -690,7 +713,9 @@ describe Projects::MergeRequestsController do
end
context 'when the path does not exist in the diff' do
- before { 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' }) }
+ 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)
@@ -913,7 +938,9 @@ describe Projects::MergeRequestsController do
end
context 'when the file does not exist cannot be resolved in the UI' do
- before { conflict_for_path('files/ruby/regexp.rb') }
+ 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)
@@ -923,7 +950,9 @@ describe Projects::MergeRequestsController do
context 'with an existing file' do
let(:path) { 'files/ruby/regex.rb' }
- before { conflict_for_path(path) }
+ before do
+ conflict_for_path(path)
+ end
it 'returns a 200 status code' do
expect(response).to have_http_status(:ok)
@@ -1195,7 +1224,9 @@ describe Projects::MergeRequestsController do
end
context 'when head_pipeline does not exist' do
- before { get_pipeline_status }
+ before do
+ get_pipeline_status
+ end
it 'return empty' do
expect(response).to have_http_status(:ok)
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index c880da1e36a..734532668d3 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -5,9 +5,12 @@ describe Projects::PipelinesController do
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public) }
+ let(:feature) { ProjectFeature::DISABLED }
before do
project.add_developer(user)
+ project.project_feature.update(
+ builds_access_level: feature)
sign_in(user)
end
@@ -49,21 +52,14 @@ describe Projects::PipelinesController do
expect(json_response['details']).to have_key 'stages'
end
- context 'when the pipeline has multiple stages and groups' do
+ context 'when the pipeline has multiple stages and groups', :request_store do
before do
- RequestStore.begin!
-
create_build('build', 0, 'build')
create_build('test', 1, 'rspec 0')
create_build('deploy', 2, 'production')
create_build('post deploy', 3, 'pages 0')
end
- after do
- RequestStore.end!
- RequestStore.clear!
- end
-
let(:project) { create(:project) }
let(:pipeline) do
create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id)
@@ -160,16 +156,26 @@ describe Projects::PipelinesController do
format: :json
end
- it 'retries a pipeline without returning any content' do
- expect(response).to have_http_status(:no_content)
- expect(build.reload).to be_retried
+ 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
+ end
+ end
+
+ context 'when builds are disabled' do
+ it 'fails to retry pipeline' do
+ expect(response).to have_http_status(:not_found)
+ end
end
end
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,
@@ -177,9 +183,19 @@ describe Projects::PipelinesController do
format: :json
end
- it 'cancels a pipeline without returning any content' do
- expect(response).to have_http_status(:no_content)
- expect(pipeline.reload).to be_canceled
+ 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
+ end
+ end
+
+ context 'when builds are disabled' do
+ it 'fails to retry pipeline' do
+ expect(response).to have_http_status(:not_found)
+ end
end
end
end
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 2294d5df581..f2b59ba82ca 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -16,10 +16,14 @@ describe Projects::ProjectMembersController do
describe 'POST create' do
let(:project_user) { create(:user) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when user does not have enough rights' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'returns 404' do
post :create, namespace_id: project.namespace,
@@ -33,7 +37,9 @@ describe Projects::ProjectMembersController do
end
context 'when user has enough rights' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(status: :success)
@@ -64,7 +70,9 @@ describe Projects::ProjectMembersController do
describe 'DELETE destroy' do
let(:member) { create(:project_member, :developer, project: project) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -78,7 +86,9 @@ describe Projects::ProjectMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'returns 404' do
delete :destroy, namespace_id: project.namespace,
@@ -91,7 +101,9 @@ describe Projects::ProjectMembersController do
end
context 'when user has enough rights' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it '[HTML] removes user from members' do
delete :destroy, namespace_id: project.namespace,
@@ -117,7 +129,9 @@ describe Projects::ProjectMembersController do
end
describe 'DELETE leave' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -130,7 +144,9 @@ describe Projects::ProjectMembersController do
context 'when member is found' do
context 'and is not an owner' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'removes user from members' do
delete :leave, namespace_id: project.namespace,
@@ -145,7 +161,9 @@ describe Projects::ProjectMembersController do
context 'and is an owner' do
let(:project) { create(:empty_project, namespace: user.namespace) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'cannot remove himself from the project' do
delete :leave, namespace_id: project.namespace,
@@ -156,7 +174,9 @@ describe Projects::ProjectMembersController do
end
context 'and is a requester' do
- before { project.request_access(user) }
+ before do
+ project.request_access(user)
+ end
it 'removes user from members' do
delete :leave, namespace_id: project.namespace,
@@ -172,7 +192,9 @@ describe Projects::ProjectMembersController do
end
describe 'POST request_access' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'creates a new ProjectMember that is not a team member' do
post :request_access, namespace_id: project.namespace,
@@ -190,7 +212,9 @@ describe Projects::ProjectMembersController do
describe 'POST approve' do
let(:member) { create(:project_member, :access_request, project: project) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when member is not found' do
it 'returns 404' do
@@ -204,7 +228,9 @@ describe Projects::ProjectMembersController do
context 'when member is found' do
context 'when user does not have enough rights' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'returns 404' do
post :approve_access_request, namespace_id: project.namespace,
@@ -217,7 +243,9 @@ describe Projects::ProjectMembersController do
end
context 'when user has enough rights' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
post :approve_access_request, namespace_id: project.namespace,
@@ -252,7 +280,10 @@ describe Projects::ProjectMembersController do
end
context 'when user can access source project members' do
- before { another_project.team << [user, :guest] }
+ before do
+ another_project.team << [user, :guest]
+ end
+
include_context 'import applied'
it 'imports source project members' do
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index 24a59caff4e..2434f822c6f 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -46,7 +46,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as the author' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders the snippet' do
get :index, namespace_id: project.namespace, project_id: project
@@ -57,7 +59,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as a project member' do
- before { sign_in(user2) }
+ before do
+ sign_in(user2)
+ end
it 'renders the snippet' do
get :index, namespace_id: project.namespace, project_id: project
@@ -78,8 +82,18 @@ describe Projects::SnippetsController do
post :create, {
namespace_id: project.namespace.to_param,
project_id: project,
- project_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params)
+ project_snippet: { title: 'Title', content: 'Content', description: 'Description' }.merge(snippet_params)
}.merge(additional_params)
+
+ Snippet.last
+ end
+
+ it 'creates the snippet correctly' do
+ snippet = create_snippet(project, visibility_level: Snippet::PRIVATE)
+
+ expect(snippet.title).to eq('Title')
+ expect(snippet.content).to eq('Content')
+ expect(snippet.description).to eq('Description')
end
context 'when the snippet is spam' do
@@ -307,7 +321,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as the author' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders the snippet' do
get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param
@@ -318,7 +334,9 @@ describe Projects::SnippetsController do
end
context 'when signed in as a project member' do
- before { sign_in(user2) }
+ before do
+ sign_in(user2)
+ end
it 'renders the snippet' do
get action, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param
@@ -339,7 +357,9 @@ describe Projects::SnippetsController do
end
context 'when signed in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'responds with status 404' do
get action, namespace_id: project.namespace, project_id: project, id: 42
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index fc97bac64cd..c48f41ca12e 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -6,7 +6,9 @@ describe Projects::TagsController do
let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') }
describe 'GET index' do
- before { get :index, namespace_id: project.namespace.to_param, project_id: project }
+ before do
+ get :index, namespace_id: project.namespace.to_param, project_id: project
+ end
it 'returns the tags for the page' do
expect(assigns(:tags).map(&:name)).to eq(['v1.1.0', 'v1.0.0'])
@@ -19,7 +21,9 @@ describe Projects::TagsController do
end
describe 'GET show' do
- before { get :show, namespace_id: project.namespace.to_param, project_id: project, id: id }
+ before do
+ get :show, namespace_id: project.namespace.to_param, project_id: project, id: id
+ end
context "valid tag" do
let(:id) { 'v1.0.0' }
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 4f6fc6691be..240a81367d0 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -29,7 +29,9 @@ describe ProjectsController do
describe "GET show" do
context "user not project member" do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context "user does not have access to project" do
let(:private_project) { create(:empty_project, :private) }
@@ -108,7 +110,9 @@ describe ProjectsController do
context "project with empty repo" do
let(:empty_project) { create(:project_empty_repo, :public) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
User.project_views.keys.each do |project_view|
context "with #{project_view} view set" do
@@ -128,7 +132,9 @@ describe ProjectsController do
context "project with broken repo" do
let(:empty_project) { create(:project_broken_repo, :public) }
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
User.project_views.keys.each do |project_view|
context "with #{project_view} view set" do
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 3173aae664c..a3708ad0908 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -18,7 +18,9 @@ describe SearchController do
context 'on restricted projects' do
context 'when signed out' do
- before { sign_out(user) }
+ before do
+ sign_out(user)
+ end
it "doesn't expose comments on issues" do
project = create(:empty_project, :public, :issues_private)
diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb
index 954fc2eaf21..0cc8a3b68eb 100644
--- a/spec/controllers/sent_notifications_controller_spec.rb
+++ b/spec/controllers/sent_notifications_controller_spec.rb
@@ -14,7 +14,9 @@ describe SentNotificationsController, type: :controller do
describe 'GET unsubscribe' do
context 'when the user is not logged in' do
context 'when the force param is passed' do
- before { get(:unsubscribe, id: sent_notification.reply_key, force: true) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key, force: true)
+ end
it 'unsubscribes the user' do
expect(issue.subscribed?(user, project)).to be_falsey
@@ -30,7 +32,9 @@ describe SentNotificationsController, type: :controller do
end
context 'when the force param is not passed' do
- before { get(:unsubscribe, id: sent_notification.reply_key) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key)
+ end
it 'does not unsubscribe the user' do
expect(issue.subscribed?(user, project)).to be_truthy
@@ -47,10 +51,14 @@ describe SentNotificationsController, type: :controller do
end
context 'when the user is logged in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
context 'when the ID passed does not exist' do
- before { get(:unsubscribe, id: sent_notification.reply_key.reverse) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key.reverse)
+ end
it 'does not unsubscribe the user' do
expect(issue.subscribed?(user, project)).to be_truthy
@@ -66,7 +74,9 @@ describe SentNotificationsController, type: :controller do
end
context 'when the force param is passed' do
- before { get(:unsubscribe, id: sent_notification.reply_key, force: true) }
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key, force: true)
+ end
it 'unsubscribes the user' do
expect(issue.subscribed?(user, project)).to be_falsey
@@ -89,7 +99,10 @@ describe SentNotificationsController, type: :controller do
end
end
let(:sent_notification) { create(:sent_notification, project: project, noteable: merge_request, recipient: user) }
- before { get(:unsubscribe, id: sent_notification.reply_key) }
+
+ before do
+ get(:unsubscribe, id: sent_notification.reply_key)
+ end
it 'unsubscribes the user' do
expect(merge_request.subscribed?(user, project)).to be_falsey
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index e87e24a33a1..03f4b0ba343 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -142,7 +142,9 @@ describe SessionsController do
end
context 'when OTP is invalid' do
- before { authenticate_2fa(otp_attempt: 'invalid') }
+ before do
+ authenticate_2fa(otp_attempt: 'invalid')
+ end
it 'does not authenticate' do
expect(subject.current_user).not_to eq user
@@ -169,7 +171,9 @@ describe SessionsController do
end
context 'when OTP is invalid' do
- before { authenticate_2fa(otp_attempt: 'invalid') }
+ before do
+ authenticate_2fa(otp_attempt: 'invalid')
+ end
it 'does not authenticate' do
expect(subject.current_user).not_to eq user
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 930415a4778..b1339b2a185 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -171,12 +171,50 @@ describe SnippetsController do
sign_in(user)
post :create, {
- personal_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params)
+ personal_snippet: { title: 'Title', content: 'Content', description: 'Description' }.merge(snippet_params)
}.merge(additional_params)
Snippet.last
end
+ it 'creates the snippet correctly' do
+ snippet = create_snippet(visibility_level: Snippet::PRIVATE)
+
+ expect(snippet.title).to eq('Title')
+ expect(snippet.content).to eq('Content')
+ expect(snippet.description).to eq('Description')
+ 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(:description) do
+ "Description with picture: ![picture](/uploads#{picture_file}) and "\
+ "text: [text.txt](/uploads#{text_file})"
+ end
+
+ before do
+ allow(FileUtils).to receive(:mkdir_p)
+ allow(FileUtils).to receive(:move)
+ end
+
+ subject { create_snippet({ description: description }, { files: [picture_file, text_file] }) }
+
+ it 'creates the snippet' do
+ expect { subject }.to change { Snippet.count }.by(1)
+ end
+
+ it 'stores the snippet description correctly' 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)"
+
+ expect(snippet.description).to eq(expected_description)
+ end
+ end
+
context 'when the snippet is spam' do
before do
allow_any_instance_of(AkismetService).to receive(:is_spam?).and_return(true)
@@ -399,7 +437,9 @@ describe SnippetsController do
end
context 'when signed in user is the author' do
- before { get :raw, id: personal_snippet.to_param }
+ before do
+ get :raw, id: personal_snippet.to_param
+ end
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(personal_snippet)
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 8000c9dec61..01a0659479b 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -92,6 +92,40 @@ describe UploadsController do
end
end
end
+
+ context 'temporal with valid image' do
+ subject do
+ post :create, model: 'personal_snippet', file: jpg, format: :json
+ end
+
+ it 'returns a content with original filename, new link, and correct type.' do
+ subject
+
+ expect(response.body).to match '\"alt\":\"rails_sample\"'
+ expect(response.body).to match "\"url\":\"/uploads/temp"
+ end
+
+ it 'does not create an Upload record' do
+ expect { subject }.not_to change { Upload.count }
+ end
+ end
+
+ context 'temporal with valid non-image file' do
+ subject do
+ post :create, model: 'personal_snippet', file: txt, format: :json
+ end
+
+ it 'returns a content with original filename, new link, and correct type.' do
+ subject
+
+ expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
+ expect(response.body).to match "\"url\":\"/uploads/temp"
+ end
+
+ it 'does not create an Upload record' do
+ expect { subject }.not_to change { Upload.count }
+ end
+ end
end
end
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index d33e2ba1e53..842d82cdbe9 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -43,7 +43,9 @@ describe UsersController do
end
context 'when logged in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders show' do
get :show, username: user.username
@@ -62,7 +64,9 @@ describe UsersController do
end
context 'when logged in' do
- before { sign_in(user) }
+ before do
+ sign_in(user)
+ end
it 'renders 404' do
get :show, username: 'nonexistent'
diff --git a/spec/db/production/settings.rb b/spec/db/production/settings.rb
deleted file mode 100644
index 3cbb173c4cc..00000000000
--- a/spec/db/production/settings.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-describe 'seed production settings', lib: true do
- include StubENV
-
- context 'GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN is set in the environment' do
- before do
- stub_env('GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN', '013456789')
- end
-
- it 'writes the token to the database' do
- load(File.join(__dir__, '../../../db/fixtures/production/010_settings.rb'))
- expect(ApplicationSetting.current.runners_registration_token).to eq('013456789')
- end
- end
-end
diff --git a/spec/db/production/settings_spec.rb b/spec/db/production/settings_spec.rb
new file mode 100644
index 00000000000..a9d015e0666
--- /dev/null
+++ b/spec/db/production/settings_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+require 'rainbow/ext/string'
+
+describe 'seed production settings', lib: true do
+ include StubENV
+ let(:settings_file) { Rails.root.join('db/fixtures/production/010_settings.rb') }
+ let(:settings) { Gitlab::CurrentSettings.current_application_settings }
+
+ context 'GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN is set in the environment' do
+ before do
+ stub_env('GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN', '013456789')
+ end
+
+ it 'writes the token to the database' do
+ load(settings_file)
+
+ expect(settings.runners_registration_token).to eq('013456789')
+ end
+ end
+
+ context 'GITLAB_PROMETHEUS_METRICS_ENABLED is set in the environment' do
+ context 'GITLAB_PROMETHEUS_METRICS_ENABLED is true' do
+ before do
+ stub_env('GITLAB_PROMETHEUS_METRICS_ENABLED', 'true')
+ end
+
+ it 'prometheus_metrics_enabled is set to true ' do
+ load(settings_file)
+
+ expect(settings.prometheus_metrics_enabled).to eq(true)
+ end
+ end
+
+ context 'GITLAB_PROMETHEUS_METRICS_ENABLED is false' do
+ before do
+ stub_env('GITLAB_PROMETHEUS_METRICS_ENABLED', 'false')
+ end
+
+ it 'prometheus_metrics_enabled is set to false' do
+ load(settings_file)
+
+ expect(settings.prometheus_metrics_enabled).to eq(false)
+ end
+ end
+
+ context 'GITLAB_PROMETHEUS_METRICS_ENABLED is false' do
+ before do
+ stub_env('GITLAB_PROMETHEUS_METRICS_ENABLED', '')
+ end
+
+ it 'prometheus_metrics_enabled is set to false' do
+ load(settings_file)
+
+ expect(settings.prometheus_metrics_enabled).to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 0bb5a86d9b9..0cc498f0ce9 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -194,8 +194,8 @@ FactoryGirl.define do
trait :extended_options do
options do
{
- image: 'ruby:2.1',
- services: ['postgres'],
+ image: { name: 'ruby:2.1', entrypoint: '/bin/sh' },
+ services: ['postgres', { name: 'docker:dind', entrypoint: '/bin/sh', command: 'sleep 30', alias: 'docker' }],
after_script: %w(ls date),
artifacts: {
name: 'artifacts_file',
diff --git a/spec/factories/ci/stages.rb b/spec/factories/ci/stages.rb
index d37eabb3e8c..d3c8bf9d54f 100644
--- a/spec/factories/ci/stages.rb
+++ b/spec/factories/ci/stages.rb
@@ -1,5 +1,5 @@
FactoryGirl.define do
- factory :ci_stage, class: Ci::Stage do
+ factory :ci_stage, class: Ci::LegacyStage do
skip_create
transient do
@@ -10,7 +10,9 @@ FactoryGirl.define do
end
initialize_with do
- Ci::Stage.new(pipeline, name: name, status: status, warnings: warnings)
+ Ci::LegacyStage.new(pipeline, name: name,
+ status: status,
+ warnings: warnings)
end
end
end
diff --git a/spec/factories/lists.rb b/spec/factories/lists.rb
index f6a78811cbe..48142d3c49b 100644
--- a/spec/factories/lists.rb
+++ b/spec/factories/lists.rb
@@ -6,6 +6,12 @@ FactoryGirl.define do
sequence(:position)
end
+ factory :backlog_list, parent: :list do
+ list_type :backlog
+ label nil
+ position nil
+ end
+
factory :closed_list, parent: :list do
list_type :closed
label nil
diff --git a/spec/factories/snippets.rb b/spec/factories/snippets.rb
index 18cb0f5de26..388f662e6e5 100644
--- a/spec/factories/snippets.rb
+++ b/spec/factories/snippets.rb
@@ -3,6 +3,7 @@ FactoryGirl.define do
author
title { generate(:title) }
content { generate(:title) }
+ description { generate(:title) }
file_name { generate(:filename) }
trait :public do
diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb
new file mode 100644
index 00000000000..1383420fb44
--- /dev/null
+++ b/spec/factories/uploads.rb
@@ -0,0 +1,8 @@
+FactoryGirl.define do
+ factory :upload do
+ model { build(:project) }
+ path { "uploads/system/project/avatar/avatar.jpg" }
+ size 100.kilobytes
+ uploader "AvatarUploader"
+ end
+end
diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb
index 96d715ef383..595366ce352 100644
--- a/spec/features/admin/admin_appearance_spec.rb
+++ b/spec/features/admin/admin_appearance_spec.rb
@@ -63,11 +63,11 @@ feature 'Admin Appearance', feature: true do
end
def logo_selector
- '//img[@src^="/uploads/appearance/logo"]'
+ '//img[@src^="/uploads/system/appearance/logo"]'
end
def header_logo_selector
- '//img[@src^="/uploads/appearance/header_logo"]'
+ '//img[@src^="/uploads/system/appearance/header_logo"]'
end
def logo_fixture
diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb
index c0b6995a84a..5f5fa4e932a 100644
--- a/spec/features/admin/admin_deploy_keys_spec.rb
+++ b/spec/features/admin/admin_deploy_keys_spec.rb
@@ -11,40 +11,67 @@ RSpec.describe 'admin deploy keys', type: :feature do
it 'show all public deploy keys' do
visit admin_deploy_keys_path
- expect(page).to have_content(deploy_key.title)
- expect(page).to have_content(another_deploy_key.title)
+ page.within(find('.deploy-keys-list', match: :first)) do
+ expect(page).to have_content(deploy_key.title)
+ expect(page).to have_content(another_deploy_key.title)
+ end
end
- describe 'create new deploy key' do
+ describe 'create a new deploy key' do
+ let(:new_ssh_key) { attributes_for(:key)[:key] }
+
before do
visit admin_deploy_keys_path
click_link 'New deploy key'
end
- it 'creates new deploy key' do
- fill_deploy_key
+ it 'creates a new deploy key' do
+ fill_in 'deploy_key_title', with: 'laptop'
+ fill_in 'deploy_key_key', with: new_ssh_key
+ check 'deploy_key_can_push'
click_button 'Create'
- expect_renders_new_key
- end
+ expect(current_path).to eq admin_deploy_keys_path
- it 'creates new deploy key with write access' do
- fill_deploy_key
- check "deploy_key_can_push"
- click_button "Create"
+ page.within(find('.deploy-keys-list', match: :first)) do
+ expect(page).to have_content('laptop')
+ expect(page).to have_content('Yes')
+ end
+ end
+ end
- expect_renders_new_key
- expect(page).to have_content('Yes')
+ describe 'update an existing deploy key' do
+ before do
+ visit admin_deploy_keys_path
+ find('tr', text: deploy_key.title).click_link('Edit')
end
- def expect_renders_new_key
+ it 'updates an existing deploy key' do
+ fill_in 'deploy_key_title', with: 'new-title'
+ check 'deploy_key_can_push'
+ click_button 'Save changes'
+
expect(current_path).to eq admin_deploy_keys_path
- expect(page).to have_content('laptop')
+
+ page.within(find('.deploy-keys-list', match: :first)) do
+ expect(page).to have_content('new-title')
+ expect(page).to have_content('Yes')
+ end
end
+ end
- def fill_deploy_key
- fill_in 'deploy_key_title', with: 'laptop'
- fill_in 'deploy_key_key', with: 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop'
+ describe 'remove an existing deploy key' do
+ before do
+ visit admin_deploy_keys_path
+ end
+
+ it 'removes an existing deploy key' do
+ find('tr', text: deploy_key.title).click_link('Remove')
+
+ expect(current_path).to eq admin_deploy_keys_path
+ page.within(find('.deploy-keys-list', match: :first)) do
+ expect(page).not_to have_content(deploy_key.title)
+ end
end
end
end
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index d5f595894d6..cf9d7bca255 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -24,7 +24,9 @@ feature 'Admin Groups', feature: true do
it 'creates new group' do
visit admin_groups_path
- click_link "New group"
+ page.within '#content-body' do
+ click_link "New group"
+ end
path_component = 'gitlab'
group_name = 'GitLab group name'
group_description = 'Description of group for GitLab'
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 5dcc7d35d82..bc11b090fdb 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -134,7 +134,10 @@ describe "Admin Runners" do
describe 'runners registration token' do
let!(:token) { current_application_settings.runners_registration_token }
- before { visit admin_runners_path }
+
+ before do
+ visit admin_runners_path
+ end
it 'has a registration token' do
expect(page).to have_content("Registration token is #{token}")
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 5099441dce2..27bc25be580 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -20,10 +20,15 @@ feature 'Admin updates settings', feature: true do
uncheck 'Gravatar enabled'
fill_in 'Home page URL', with: 'https://about.gitlab.com/'
fill_in 'Help page text', with: 'Example text'
+ check 'Hide marketing-related entries from help'
+ fill_in 'Support page URL', with: 'http://example.com/help'
click_button 'Save'
expect(current_application_settings.gravatar_enabled).to be_falsey
expect(current_application_settings.home_page_url).to eq "https://about.gitlab.com/"
+ expect(current_application_settings.help_page_text).to eq "Example text"
+ expect(current_application_settings.help_page_hide_commercial_content).to be_truthy
+ expect(current_application_settings.help_page_support_url).to eq "http://example.com/help"
expect(page).to have_content "Application settings saved successfully"
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 0fb4baeb71c..849ec829f75 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -12,7 +12,9 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
find(".table.inactive-tokens")
end
- before { login_as(admin) }
+ before do
+ login_as(admin)
+ end
describe "token creation" do
it "allows creation of a token" do
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 301a47169a4..f72651667ee 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -124,7 +124,10 @@ describe "Admin::Users", feature: true do
describe 'Impersonation' do
let(:another_user) { create(:user) }
- before { visit admin_user_path(another_user) }
+
+ before do
+ visit admin_user_path(another_user)
+ end
context 'before impersonating' do
it 'shows impersonate button for other users' do
@@ -149,7 +152,9 @@ describe "Admin::Users", feature: true do
end
context 'when impersonating' do
- before { click_link 'Impersonate' }
+ before do
+ click_link 'Impersonate'
+ end
it 'logs in as the user when impersonate is clicked' do
expect(page.find(:css, '.header-user .profile-link')['data-user']).to eql(another_user.username)
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index 32ac265814f..2b8edac4f10 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -231,7 +231,7 @@ describe 'Issue Boards add issue modal', :feature, :js do
click_button 'Add 1 issue'
end
- page.within(first('.board')) do
+ page.within(find('.board:nth-child(2)')) do
expect(page).to have_selector('.card')
end
end
@@ -247,7 +247,7 @@ describe 'Issue Boards add issue modal', :feature, :js do
click_button 'Add 1 issue'
end
- page.within(find('.board:nth-child(2)')) do
+ page.within(find('.board:nth-child(3)')) do
expect(page).to have_selector('.card')
end
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index ba27db23ced..968cc9d9c80 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -19,7 +19,7 @@ describe 'Issue Boards', feature: true, js: true do
before do
visit namespace_project_board_path(project.namespace, project, board)
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 3)
end
it 'shows blank state' do
@@ -36,18 +36,18 @@ describe 'Issue Boards', feature: true, js: true do
page.within(find('.board-blank-state')) do
click_button("Nevermind, I'll use my own")
end
- expect(page).to have_selector('.board', count: 1)
+ expect(page).to have_selector('.board', count: 2)
end
it 'creates default lists' do
- lists = ['To Do', 'Doing', 'Closed']
+ lists = ['Backlog', 'To Do', 'Doing', 'Closed']
page.within(find('.board-blank-state')) do
click_button('Add default lists')
end
wait_for_requests
- expect(page).to have_selector('.board', count: 3)
+ expect(page).to have_selector('.board', count: 4)
page.all('.board').each_with_index do |list, i|
expect(list.find('.board-title')).to have_content(lists[i])
@@ -85,29 +85,25 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- expect(page).to have_selector('.board', count: 3)
- expect(find('.board:nth-child(1)')).to have_selector('.card')
+ expect(page).to have_selector('.board', count: 4)
expect(find('.board:nth-child(2)')).to have_selector('.card')
expect(find('.board:nth-child(3)')).to have_selector('.card')
- end
-
- it 'shows lists' do
- expect(page).to have_selector('.board', count: 3)
+ expect(find('.board:nth-child(4)')).to have_selector('.card')
end
it 'shows description tooltip on list title' do
- page.within('.board:nth-child(1)') do
+ page.within('.board:nth-child(2)') do
expect(find('.board-title span.has-tooltip')[:title]).to eq('Test')
end
end
it 'shows issues in lists' do
- wait_for_board_cards(1, 8)
- wait_for_board_cards(2, 2)
+ wait_for_board_cards(2, 8)
+ wait_for_board_cards(3, 2)
end
it 'shows confidential issues with icon' do
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
expect(page).to have_selector('.confidential-icon', count: 1)
end
end
@@ -118,9 +114,9 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- expect(find('.board:nth-child(1)')).to have_selector('.card', count: 0)
expect(find('.board:nth-child(2)')).to have_selector('.card', count: 0)
- expect(find('.board:nth-child(3)')).to have_selector('.card', count: 1)
+ expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0)
+ expect(find('.board:nth-child(4)')).to have_selector('.card', count: 1)
end
it 'search list' do
@@ -129,32 +125,32 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- expect(find('.board:nth-child(1)')).to have_selector('.card', count: 1)
- expect(find('.board:nth-child(2)')).to have_selector('.card', count: 0)
+ expect(find('.board:nth-child(2)')).to have_selector('.card', count: 1)
expect(find('.board:nth-child(3)')).to have_selector('.card', count: 0)
+ expect(find('.board:nth-child(4)')).to have_selector('.card', count: 0)
end
it 'allows user to delete board' do
- page.within(find('.board:nth-child(1)')) do
+ page.within(find('.board:nth-child(2)')) do
find('.board-delete').click
end
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 3)
end
it 'removes checkmark in new list dropdown after deleting' do
click_button 'Add list'
wait_for_requests
- page.within(find('.board:nth-child(1)')) do
+ page.within(find('.board:nth-child(2)')) do
find('.board-delete').click
end
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 3)
end
it 'infinite scrolls list' do
@@ -165,18 +161,18 @@ describe 'Issue Boards', feature: true, js: true do
visit namespace_project_board_path(project.namespace, project, board)
wait_for_requests
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
expect(page.find('.board-header')).to have_content('58')
expect(page).to have_selector('.card', count: 20)
expect(page).to have_content('Showing 20 of 58 issues')
- evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight")
+ evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
wait_for_requests
expect(page).to have_selector('.card', count: 40)
expect(page).to have_content('Showing 40 of 58 issues')
- evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight")
+ evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
wait_for_requests
expect(page).to have_selector('.card', count: 58)
@@ -186,83 +182,83 @@ describe 'Issue Boards', feature: true, js: true do
context 'closed' do
it 'shows list of closed issues' do
- wait_for_board_cards(3, 1)
+ wait_for_board_cards(4, 1)
wait_for_requests
end
it 'moves issue to closed' do
- drag(list_from_index: 0, list_to_index: 2)
+ drag(list_from_index: 1, list_to_index: 3)
- wait_for_board_cards(1, 7)
- wait_for_board_cards(2, 2)
+ wait_for_board_cards(2, 7)
wait_for_board_cards(3, 2)
+ wait_for_board_cards(4, 2)
- expect(find('.board:nth-child(1)')).not_to have_content(issue9.title)
- expect(find('.board:nth-child(3)')).to have_selector('.card', count: 2)
- expect(find('.board:nth-child(3)')).to have_content(issue9.title)
- expect(find('.board:nth-child(3)')).not_to have_content(planning.title)
+ expect(find('.board:nth-child(2)')).not_to have_content(issue9.title)
+ expect(find('.board:nth-child(4)')).to have_selector('.card', count: 2)
+ expect(find('.board:nth-child(4)')).to have_content(issue9.title)
+ expect(find('.board:nth-child(4)')).not_to have_content(planning.title)
end
it 'removes all of the same issue to closed' do
- drag(list_from_index: 0, list_to_index: 2)
+ drag(list_from_index: 1, list_to_index: 3)
- wait_for_board_cards(1, 7)
- wait_for_board_cards(2, 2)
+ wait_for_board_cards(2, 7)
wait_for_board_cards(3, 2)
+ wait_for_board_cards(4, 2)
- expect(find('.board:nth-child(1)')).not_to have_content(issue9.title)
- expect(find('.board:nth-child(3)')).to have_content(issue9.title)
- expect(find('.board:nth-child(3)')).not_to have_content(planning.title)
+ expect(find('.board:nth-child(2)')).not_to have_content(issue9.title)
+ expect(find('.board:nth-child(4)')).to have_content(issue9.title)
+ expect(find('.board:nth-child(4)')).not_to have_content(planning.title)
end
end
context 'lists' do
it 'changes position of list' do
- drag(list_from_index: 1, list_to_index: 0, selector: '.board-header')
+ drag(list_from_index: 2, list_to_index: 1, selector: '.board-header')
- wait_for_board_cards(1, 2)
- wait_for_board_cards(2, 8)
- wait_for_board_cards(3, 1)
+ wait_for_board_cards(2, 2)
+ wait_for_board_cards(3, 8)
+ wait_for_board_cards(4, 1)
- expect(find('.board:nth-child(1)')).to have_content(development.title)
- expect(find('.board:nth-child(1)')).to have_content(planning.title)
+ expect(find('.board:nth-child(2)')).to have_content(development.title)
+ expect(find('.board:nth-child(2)')).to have_content(planning.title)
end
it 'issue moves between lists' do
- drag(list_from_index: 0, from_index: 1, list_to_index: 1)
+ drag(list_from_index: 1, from_index: 1, list_to_index: 2)
- wait_for_board_cards(1, 7)
- wait_for_board_cards(2, 2)
- wait_for_board_cards(3, 1)
+ wait_for_board_cards(2, 7)
+ wait_for_board_cards(3, 2)
+ wait_for_board_cards(4, 1)
- expect(find('.board:nth-child(2)')).to have_content(issue6.title)
- expect(find('.board:nth-child(2)').all('.card').last).not_to have_content(development.title)
+ expect(find('.board:nth-child(3)')).to have_content(issue6.title)
+ expect(find('.board:nth-child(3)').all('.card').last).not_to have_content(development.title)
end
it 'issue moves between lists' do
- drag(list_from_index: 1, list_to_index: 0)
+ drag(list_from_index: 2, list_to_index: 1)
- wait_for_board_cards(1, 9)
- wait_for_board_cards(2, 1)
+ wait_for_board_cards(2, 9)
wait_for_board_cards(3, 1)
+ wait_for_board_cards(4, 1)
- expect(find('.board:nth-child(1)')).to have_content(issue7.title)
- expect(find('.board:nth-child(1)').all('.card').first).not_to have_content(planning.title)
+ expect(find('.board:nth-child(2)')).to have_content(issue7.title)
+ expect(find('.board:nth-child(2)').all('.card').first).not_to have_content(planning.title)
end
it 'issue moves from closed' do
- drag(list_from_index: 2, list_to_index: 1)
+ drag(list_from_index: 3, list_to_index: 2)
- expect(find('.board:nth-child(2)')).to have_content(issue8.title)
+ wait_for_board_cards(2, 8)
+ wait_for_board_cards(3, 3)
+ wait_for_board_cards(4, 0)
- wait_for_board_cards(1, 8)
- wait_for_board_cards(2, 3)
- wait_for_board_cards(3, 0)
+ expect(find('.board:nth-child(3)')).to have_content(issue8.title)
end
context 'issue card' do
it 'shows assignee' do
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
expect(page).to have_selector('.avatar', count: 1)
end
end
@@ -290,7 +286,7 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- expect(page).to have_selector('.board', count: 4)
+ expect(page).to have_selector('.board', count: 5)
end
it 'creates new list for Backlog label' do
@@ -303,7 +299,7 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- expect(page).to have_selector('.board', count: 4)
+ expect(page).to have_selector('.board', count: 5)
end
it 'creates new list for Closed label' do
@@ -316,7 +312,7 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- expect(page).to have_selector('.board', count: 4)
+ expect(page).to have_selector('.board', count: 5)
end
it 'keeps dropdown open after adding new list' do
@@ -348,7 +344,7 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
wait_for_requests
- expect(page).to have_selector('.board', count: 4)
+ expect(page).to have_selector('.board', count: 5)
end
end
end
@@ -360,8 +356,8 @@ describe 'Issue Boards', feature: true, js: true do
submit_filter
wait_for_requests
- wait_for_board_cards(1, 1)
- wait_for_empty_boards((2..3))
+ wait_for_board_cards(2, 1)
+ wait_for_empty_boards((3..4))
end
it 'filters by assignee' do
@@ -371,8 +367,8 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- wait_for_board_cards(1, 1)
- wait_for_empty_boards((2..3))
+ wait_for_board_cards(2, 1)
+ wait_for_empty_boards((3..4))
end
it 'filters by milestone' do
@@ -381,9 +377,9 @@ describe 'Issue Boards', feature: true, js: true do
submit_filter
wait_for_requests
- wait_for_board_cards(1, 1)
- wait_for_board_cards(2, 0)
+ wait_for_board_cards(2, 1)
wait_for_board_cards(3, 0)
+ wait_for_board_cards(4, 0)
end
it 'filters by label' do
@@ -392,8 +388,8 @@ describe 'Issue Boards', feature: true, js: true do
submit_filter
wait_for_requests
- wait_for_board_cards(1, 1)
- wait_for_empty_boards((2..3))
+ wait_for_board_cards(2, 1)
+ wait_for_empty_boards((3..4))
end
it 'filters by label with space after reload' do
@@ -403,17 +399,17 @@ describe 'Issue Boards', feature: true, js: true do
# Test after reload
page.evaluate_script 'window.location.reload()'
- wait_for_board_cards(1, 1)
- wait_for_empty_boards((2..3))
+ wait_for_board_cards(2, 1)
+ wait_for_empty_boards((3..4))
wait_for_requests
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
expect(page.find('.board-header')).to have_content('1')
expect(page).to have_selector('.card', count: 1)
end
- page.within(find('.board:nth-child(2)')) do
+ page.within(find('.board:nth-child(3)')) do
expect(page.find('.board-header')).to have_content('0')
expect(page).to have_selector('.card', count: 0)
end
@@ -424,12 +420,12 @@ describe 'Issue Boards', feature: true, js: true do
click_filter_link(testing.title)
submit_filter
- wait_for_board_cards(1, 1)
+ wait_for_board_cards(2, 1)
find('.clear-search').click
submit_filter
- wait_for_board_cards(1, 8)
+ wait_for_board_cards(2, 8)
end
it 'infinite scrolls list with label filter' do
@@ -443,17 +439,17 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
expect(page.find('.board-header')).to have_content('51')
expect(page).to have_selector('.card', count: 20)
expect(page).to have_content('Showing 20 of 51 issues')
- evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight")
+ evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
expect(page).to have_selector('.card', count: 40)
expect(page).to have_content('Showing 40 of 51 issues')
- evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight")
+ evaluate_script("document.querySelectorAll('.board .board-list')[1].scrollTop = document.querySelectorAll('.board .board-list')[1].scrollHeight")
expect(page).to have_selector('.card', count: 51)
expect(page).to have_content('Showing all issues')
@@ -471,12 +467,12 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- wait_for_board_cards(1, 1)
- wait_for_empty_boards((2..3))
+ wait_for_board_cards(2, 1)
+ wait_for_empty_boards((3..4))
end
it 'filters by clicking label button on issue' do
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
expect(page).to have_selector('.card', count: 8)
expect(find('.card', match: :first)).to have_content(bug.title)
click_button(bug.title)
@@ -489,12 +485,12 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- wait_for_board_cards(1, 1)
- wait_for_empty_boards((2..3))
+ wait_for_board_cards(2, 1)
+ wait_for_empty_boards((3..4))
end
it 'removes label filter by clicking label button on issue' do
- page.within(find('.board', match: :first)) do
+ page.within(find('.board:nth-child(2)')) do
page.within(find('.card', match: :first)) do
click_button(bug.title)
end
diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb
index 6c40cb2c9eb..1c289993e28 100644
--- a/spec/features/boards/issue_ordering_spec.rb
+++ b/spec/features/boards/issue_ordering_spec.rb
@@ -25,11 +25,11 @@ describe 'Issue Boards', :feature, :js do
visit namespace_project_board_path(project.namespace, project, board)
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 3)
end
it 'has un-ordered issue as last issue' do
- page.within(first('.board')) do
+ page.within(find('.board:nth-child(2)')) do
expect(all('.card').last).to have_content(issue4.title)
end
end
@@ -39,7 +39,7 @@ describe 'Issue Boards', :feature, :js do
wait_for_requests
- page.within(first('.board')) do
+ page.within(find('.board:nth-child(2)')) do
expect(first('.card')).to have_content(issue4.title)
end
end
@@ -50,7 +50,7 @@ describe 'Issue Boards', :feature, :js do
visit namespace_project_board_path(project.namespace, project, board)
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 3)
end
it 'moves from middle to top' do
@@ -113,50 +113,50 @@ describe 'Issue Boards', :feature, :js do
visit namespace_project_board_path(project.namespace, project, board)
wait_for_requests
- expect(page).to have_selector('.board', count: 3)
+ expect(page).to have_selector('.board', count: 4)
end
it 'moves to top of another list' do
- drag(list_from_index: 0, list_to_index: 1)
+ drag(list_from_index: 1, list_to_index: 2)
wait_for_requests
- expect(first('.board')).to have_selector('.card', count: 2)
- expect(all('.board')[1]).to have_selector('.card', count: 4)
+ expect(find('.board:nth-child(2)')).to have_selector('.card', count: 2)
+ expect(all('.board')[2]).to have_selector('.card', count: 4)
- page.within(all('.board')[1]) do
+ page.within(all('.board')[2]) do
expect(first('.card')).to have_content(issue3.title)
end
end
it 'moves to bottom of another list' do
- drag(list_from_index: 0, list_to_index: 1, to_index: 2)
+ drag(list_from_index: 1, list_to_index: 2, to_index: 2)
wait_for_requests
- expect(first('.board')).to have_selector('.card', count: 2)
- expect(all('.board')[1]).to have_selector('.card', count: 4)
+ expect(find('.board:nth-child(2)')).to have_selector('.card', count: 2)
+ expect(all('.board')[2]).to have_selector('.card', count: 4)
- page.within(all('.board')[1]) do
+ page.within(all('.board')[2]) do
expect(all('.card').last).to have_content(issue3.title)
end
end
it 'moves to index of another list' do
- drag(list_from_index: 0, list_to_index: 1, to_index: 1)
+ drag(list_from_index: 1, list_to_index: 2, to_index: 1)
wait_for_requests
- expect(first('.board')).to have_selector('.card', count: 2)
- expect(all('.board')[1]).to have_selector('.card', count: 4)
+ expect(find('.board:nth-child(2)')).to have_selector('.card', count: 2)
+ expect(all('.board')[2]).to have_selector('.card', count: 4)
- page.within(all('.board')[1]) do
+ page.within(all('.board')[2]) do
expect(all('.card')[1]).to have_content(issue3.title)
end
end
end
- def drag(selector: '.board-list', list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0)
+ def drag(selector: '.board-list', list_from_index: 1, from_index: 0, to_index: 0, list_to_index: 1)
drag_to(selector: selector,
scrollable: '#board-app',
list_from_index: list_from_index,
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index 0e98f994018..7ba60247587 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -15,22 +15,22 @@ describe 'Issue Boards new issue', feature: true, js: true do
visit namespace_project_board_path(project.namespace, project, board)
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 3)
end
it 'displays new issue button' do
- expect(page).to have_selector('.board-issue-count-holder .btn', count: 1)
+ expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1)
end
it 'does not display new issue button in closed list' do
- page.within('.board:nth-child(2)') do
- expect(page).not_to have_selector('.board-issue-count-holder .btn')
+ page.within('.board:nth-child(3)') do
+ expect(page).not_to have_selector('.issue-count-badge-add-button')
end
end
it 'shows form when clicking button' do
page.within(first('.board')) do
- find('.board-issue-count-holder .btn').click
+ find('.issue-count-badge-add-button').click
expect(page).to have_selector('.board-new-issue-form')
end
@@ -38,7 +38,7 @@ describe 'Issue Boards new issue', feature: true, js: true do
it 'hides form when clicking cancel' do
page.within(first('.board')) do
- find('.board-issue-count-holder .btn').click
+ find('.issue-count-badge-add-button').click
expect(page).to have_selector('.board-new-issue-form')
@@ -50,7 +50,7 @@ describe 'Issue Boards new issue', feature: true, js: true do
it 'creates new issue' do
page.within(first('.board')) do
- find('.board-issue-count-holder .btn').click
+ find('.issue-count-badge-add-button').click
end
page.within(first('.board-new-issue-form')) do
@@ -60,14 +60,14 @@ describe 'Issue Boards new issue', feature: true, js: true do
wait_for_requests
- page.within(first('.board .board-issue-count')) do
+ page.within(first('.board .issue-count-badge-count')) do
expect(page).to have_content('1')
end
end
it 'shows sidebar when creating new issue' do
page.within(first('.board')) do
- find('.board-issue-count-holder .btn').click
+ find('.issue-count-badge-add-button').click
end
page.within(first('.board-new-issue-form')) do
@@ -88,7 +88,7 @@ describe 'Issue Boards new issue', feature: true, js: true do
end
it 'does not display new issue button' do
- expect(page).to have_selector('.board-issue-count-holder .btn', count: 0)
+ expect(page).to have_selector('.issue-count-badge-add-button', count: 0)
end
end
end
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 34f4d765117..235e4899707 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -13,7 +13,7 @@ describe 'Issue Boards', feature: true, js: true do
let!(:issue2) { create(:labeled_issue, project: project, labels: [development, stretch], relative_position: 1) }
let(:board) { create(:board, project: project) }
let!(:list) { create(:list, board: board, label: development, position: 0) }
- let(:card) { first('.board').first('.card') }
+ let(:card) { find('.board:nth-child(2)').first('.card') }
before do
Timecop.freeze
@@ -74,7 +74,7 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_requests
- page.within(first('.board')) do
+ page.within(find('.board:nth-child(2)')) do
expect(page).to have_selector('.card', count: 1)
end
end
@@ -101,7 +101,7 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'removes the assignee' do
- card_two = first('.board').find('.card:nth-child(2)')
+ card_two = find('.board:nth-child(2)').find('.card:nth-child(2)')
click_card(card_two)
page.within('.assignee') do
@@ -154,7 +154,7 @@ describe 'Issue Boards', feature: true, js: true do
expect(page).to have_content(user.name)
end
- page.within(first('.board')) do
+ page.within(find('.board:nth-child(2)')) do
find('.card:nth-child(2)').trigger('click')
end
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index b0e2953dda2..7eb254f8451 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -6,40 +6,124 @@ describe 'Dashboard Groups page', js: true, feature: true do
let!(:nested_group) { create(:group, :nested) }
let!(:another_group) { create(:group) }
- before do
+ it 'shows groups user is member of' do
group.add_owner(user)
nested_group.add_owner(user)
login_as(user)
-
visit dashboard_groups_path
- end
- it 'shows groups user is member of' do
expect(page).to have_content(group.full_name)
expect(page).to have_content(nested_group.full_name)
expect(page).not_to have_content(another_group.full_name)
end
- it 'filters groups' do
- fill_in 'filter_groups', with: group.name
- wait_for_requests
+ describe 'when filtering groups' do
+ before do
+ group.add_owner(user)
+ nested_group.add_owner(user)
- expect(page).to have_content(group.full_name)
- expect(page).not_to have_content(nested_group.full_name)
- expect(page).not_to have_content(another_group.full_name)
+ login_as(user)
+
+ visit dashboard_groups_path
+ end
+
+ it 'filters groups' do
+ fill_in 'filter_groups', with: group.name
+ wait_for_requests
+
+ expect(page).to have_content(group.full_name)
+ expect(page).not_to have_content(nested_group.full_name)
+ expect(page).not_to have_content(another_group.full_name)
+ end
+
+ it 'resets search when user cleans the input' do
+ fill_in 'filter_groups', with: group.name
+ wait_for_requests
+
+ fill_in 'filter_groups', with: ""
+ wait_for_requests
+
+ expect(page).to have_content(group.full_name)
+ expect(page).to have_content(nested_group.full_name)
+ expect(page).not_to have_content(another_group.full_name)
+ expect(page.all('.js-groups-list-holder .content-list li').length).to eq 2
+ end
end
- it 'resets search when user cleans the input' do
- fill_in 'filter_groups', with: group.name
- wait_for_requests
+ describe 'group with subgroups' do
+ let!(:subgroup) { create(:group, :public, parent: group) }
- fill_in 'filter_groups', with: ""
- wait_for_requests
+ before do
+ group.add_owner(user)
+ subgroup.add_owner(user)
- expect(page).to have_content(group.full_name)
- expect(page).to have_content(nested_group.full_name)
- expect(page).not_to have_content(another_group.full_name)
- expect(page.all('.js-groups-list-holder .content-list li').length).to eq 2
+ login_as(user)
+
+ visit dashboard_groups_path
+ end
+
+ it 'shows subgroups inside of its parent group' do
+ expect(page).to have_selector('.groups-list-tree-container .group-list-tree', count: 2)
+ expect(page).to have_selector(".groups-list-tree-container #group-#{group.id} #group-#{subgroup.id}", count: 1)
+ end
+
+ it 'can toggle parent group' do
+ # Expanded by default
+ expect(page).to have_selector("#group-#{group.id} .fa-caret-down", count: 1)
+ expect(page).not_to have_selector("#group-#{group.id} .fa-caret-right")
+
+ # Collapse
+ find("#group-#{group.id}").trigger('click')
+
+ expect(page).not_to have_selector("#group-#{group.id} .fa-caret-down")
+ expect(page).to have_selector("#group-#{group.id} .fa-caret-right", count: 1)
+ expect(page).not_to have_selector("#group-#{group.id} #group-#{subgroup.id}")
+
+ # Expand
+ find("#group-#{group.id}").trigger('click')
+
+ expect(page).to have_selector("#group-#{group.id} .fa-caret-down", count: 1)
+ expect(page).not_to have_selector("#group-#{group.id} .fa-caret-right")
+ expect(page).to have_selector("#group-#{group.id} #group-#{subgroup.id}")
+ end
+ end
+
+ describe 'when using pagination' do
+ let(:group2) { create(:group) }
+
+ before do
+ group.add_owner(user)
+ group2.add_owner(user)
+
+ allow(Kaminari.config).to receive(:default_per_page).and_return(1)
+
+ login_as(user)
+ visit dashboard_groups_path
+ end
+
+ it 'shows pagination' do
+ expect(page).to have_selector('.gl-pagination')
+ expect(page).to have_selector('.gl-pagination .page', count: 2)
+ end
+
+ it 'loads results for next page' do
+ # Check first page
+ expect(page).to have_content(group2.full_name)
+ expect(page).to have_selector("#group-#{group2.id}")
+ expect(page).not_to have_content(group.full_name)
+ expect(page).not_to have_selector("#group-#{group.id}")
+
+ # Go to next page
+ find(".gl-pagination .page:not(.active) a").trigger('click')
+
+ wait_for_requests
+
+ # Check second page
+ expect(page).to have_content(group.full_name)
+ expect(page).to have_selector("#group-#{group.id}")
+ expect(page).not_to have_content(group2.full_name)
+ expect(page).not_to have_selector("#group-#{group2.id}")
+ end
end
end
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 9cebe52c444..bcb52f602b0 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -12,7 +12,9 @@ describe 'Dashboard Merge Requests' do
end
describe 'new merge request dropdown' do
- before { visit merge_requests_dashboard_path }
+ before do
+ visit merge_requests_dashboard_path
+ end
it 'shows projects only with merge requests feature enabled', js: true do
find('.new-project-item-select-button').trigger('click')
diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb
new file mode 100644
index 00000000000..0c7b992c500
--- /dev/null
+++ b/spec/features/dashboard/milestone_tabs_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe 'Dashboard milestone tabs', :js, :feature do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let!(:label) { create(:label, project: project) }
+ let(:project_milestone) { create(:milestone, project: project) }
+ let(:milestone) do
+ DashboardMilestone.build(
+ [project],
+ project_milestone.title
+ )
+ end
+ let!(:merge_request) { create(:labeled_merge_request, source_project: project, target_project: project, milestone: project_milestone, labels: [label]) }
+
+ before do
+ project.add_master(user)
+ login_as(user)
+
+ visit dashboard_milestone_path(milestone.safe_title, title: milestone.title)
+ end
+
+ it 'loads merge requests async' do
+ click_link 'Merge Requests'
+
+ expect(page).to have_selector('.merge_requests-sortable-list')
+ end
+
+ it 'loads participants async' do
+ click_link 'Participants'
+
+ expect(page).to have_selector('#tab-participants .bordered-list')
+ end
+
+ it 'loads labels async' do
+ click_link 'Labels'
+
+ expect(page).to have_selector('#tab-labels .bordered-list')
+ end
+end
diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb
index cdf919af9b5..0ba87d921d0 100644
--- a/spec/features/dashboard/project_member_activity_index_spec.rb
+++ b/spec/features/dashboard/project_member_activity_index_spec.rb
@@ -17,19 +17,25 @@ feature 'Project member activity', feature: true, js: true do
subject { page.find(".event-title").text }
context 'when a user joins the project' do
- before { visit_activities_and_wait_with_event(Event::JOINED) }
+ before do
+ visit_activities_and_wait_with_event(Event::JOINED)
+ end
it { is_expected.to eq("#{user.name} joined project") }
end
context 'when a user leaves the project' do
- before { visit_activities_and_wait_with_event(Event::LEFT) }
+ before do
+ visit_activities_and_wait_with_event(Event::LEFT)
+ end
it { is_expected.to eq("#{user.name} left project") }
end
context 'when a users membership expires for the project' do
- before { visit_activities_and_wait_with_event(Event::EXPIRED) }
+ before do
+ visit_activities_and_wait_with_event(Event::EXPIRED)
+ end
it "presents the correct message" do
message = "#{user.name} removed due to membership expiration from project"
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index c4d5077e5e1..36b0c371e6e 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -140,7 +140,9 @@ feature 'Expand and collapse diffs', js: true, feature: true do
end
context 'reloading the page' do
- before { refresh }
+ before do
+ refresh
+ end
it 'collapses the large diff by default' do
expect(large_diff).not_to have_selector('.code')
@@ -262,7 +264,7 @@ feature 'Expand and collapse diffs', js: true, feature: true do
# Wait for elements to appear to ensure full page reload
expect(page).to have_content('This diff was suppressed by a .gitattributes entry')
- expect(page).to have_content('This diff could not be displayed because it is too large.')
+ expect(page).to have_content('This source diff could not be displayed because it is too large.')
expect(page).to have_content('too_large_image.jpg')
find('.note-textarea')
diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb
new file mode 100644
index 00000000000..15a6354211b
--- /dev/null
+++ b/spec/features/explore/new_menu_spec.rb
@@ -0,0 +1,172 @@
+require 'spec_helper'
+
+feature 'Top Plus Menu', feature: true, js: true do
+ let(:user) { create :user }
+ let(:guest_user) { create :user}
+ let(:group) { create(:group) }
+ let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
+ let(:public_project) { create(: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
+ login_as(user)
+ end
+
+ scenario 'click on New project shows new project page' do
+ visit root_dashboard_path
+
+ click_topmenuitem("New project")
+
+ expect(page).to have_content('Project path')
+ expect(page).to have_content('Project name')
+ end
+
+ scenario 'click on New group shows new group page' do
+ visit root_dashboard_path
+
+ click_topmenuitem("New group")
+
+ expect(page).to have_content('Group path')
+ expect(page).to have_content('Group name')
+ end
+
+ 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')
+ expect(page).to have_content('Title')
+ end
+
+ scenario 'click on New issue shows new issue page' do
+ visit namespace_project_path(project.namespace, project)
+
+ click_topmenuitem("New issue")
+
+ expect(page).to have_content('New Issue')
+ expect(page).to have_content('Title')
+ end
+
+ scenario 'click on New merge request shows new merge request page' do
+ visit namespace_project_path(project.namespace, project)
+
+ click_topmenuitem("New merge request")
+
+ expect(page).to have_content('New Merge Request')
+ expect(page).to have_content('Source branch')
+ expect(page).to have_content('Target branch')
+ end
+
+ scenario 'click on New project snippet shows new snippet page' do
+ visit namespace_project_path(project.namespace, project)
+
+ page.within '.header-content' do
+ find('.header-new-dropdown-toggle').trigger('click')
+ expect(page).to have_selector('.header-new.dropdown.open', count: 1)
+ find('.header-new-project-snippet a').trigger('click')
+ end
+
+ expect(page).to have_content('New Snippet')
+ expect(page).to have_content('Title')
+ end
+
+ scenario 'Click on New subgroup shows new group page' do
+ visit group_path(group)
+
+ click_topmenuitem("New subgroup")
+
+ expect(page).to have_content('Group path')
+ expect(page).to have_content('Group name')
+ end
+
+ scenario 'Click on New project in group shows new project page' do
+ visit group_path(group)
+
+ page.within '.header-content' do
+ find('.header-new-dropdown-toggle').trigger('click')
+ expect(page).to have_selector('.header-new.dropdown.open', count: 1)
+ find('.header-new-group-project a').trigger('click')
+ end
+
+ expect(page).to have_content('Project path')
+ expect(page).to have_content('Project name')
+ end
+ end
+
+ context 'used by guest user' do
+ before do
+ login_as(guest_user)
+ end
+
+ scenario 'click on New issue shows new issue page' do
+ visit namespace_project_path(project.namespace, project)
+
+ click_topmenuitem("New issue")
+
+ expect(page).to have_content('New Issue')
+ expect(page).to have_content('Title')
+ end
+
+ scenario 'has no New merge request menu item' do
+ visit namespace_project_path(project.namespace, project)
+
+ hasnot_topmenuitem("New merge request")
+ end
+
+ scenario 'has no New project snippet menu item' do
+ visit namespace_project_path(project.namespace, 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)
+
+ 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)
+
+ 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)
+
+ expect(find('.header-new.dropdown')).not_to have_selector('.header-new-project-snippet')
+ end
+
+ scenario 'has no New subgroup menu item' do
+ visit group_path(group)
+
+ hasnot_topmenuitem("New subgroup")
+ end
+
+ 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
+
+ def click_topmenuitem(item_name)
+ page.within '.header-content' do
+ find('.header-new-dropdown-toggle').trigger('click')
+ expect(page).to have_selector('.header-new.dropdown.open', count: 1)
+ click_link item_name
+ end
+ end
+
+ def hasnot_topmenuitem(item_name)
+ expect(find('.header-new.dropdown')).not_to have_content(item_name)
+ end
+end
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index cc25db4ad60..6afde1d0bed 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -52,9 +52,14 @@ feature 'Edit group settings', feature: true do
given!(:project) { create(:project, group: group, path: 'project') }
given(:old_project_full_path) { "/#{group.path}/#{project.path}" }
given(:new_project_full_path) { "/#{new_group_path}/#{project.path}" }
-
- before(:context) { TestEnv.clean_test_path }
- after(:example) { TestEnv.clean_test_path }
+
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
scenario 'the project is accessible via the new path' do
update_path(new_group_path)
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 24ea7aba0cc..5737ca39b4e 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -12,7 +12,9 @@ feature 'Group', feature: true do
end
describe 'create a group' do
- before { visit new_group_path }
+ before do
+ visit new_group_path
+ end
describe 'with space in group path' do
it 'renders new group form with validation errors' do
@@ -138,7 +140,9 @@ feature 'Group', feature: true do
let(:path) { edit_group_path(group) }
let(:new_name) { 'new-name' }
- before { visit path }
+ before do
+ visit path
+ end
it 'saves new settings' do
fill_in 'group_name', with: new_name
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index e0b2404e60a..18102146b5f 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -34,29 +34,46 @@ describe 'Help Pages', feature: true do
end
end
- context 'in a production environment with version check enabled', js: true do
+ context 'in a production environment with version check enabled', :js do
before do
allow(Rails.env).to receive(:production?) { true }
- allow(current_application_settings).to receive(:version_check_enabled) { true }
+ allow_any_instance_of(ApplicationSetting).to receive(:version_check_enabled) { true }
allow_any_instance_of(VersionCheck).to receive(:url) { '/version-check-url' }
login_as :user
visit help_path
end
- it 'should display a version check image' do
- expect(find('.js-version-status-badge')).to be_visible
+ it 'has a version check image' do
+ expect(find('.js-version-status-badge', visible: false)['src']).to end_with('/version-check-url')
end
- it 'should have a src url' do
- expect(find('.js-version-status-badge')['src']).to match(/\/version-check-url/)
+ it 'hides the version check image if the image request fails' do
+ # We use '--load-images=yes' with poltergeist so the image fails to load
+ expect(find('.js-version-status-badge', visible: false)).not_to be_visible
end
+ end
- it 'should hide the version check image if the image request fails' do
- # We use '--load-images=no' with poltergeist so we must trigger manually
- execute_script("$('.js-version-status-badge').trigger('error');")
+ describe 'when help page is customized' do
+ before do
+ allow_any_instance_of(ApplicationSetting).to receive(:help_page_hide_commercial_content?) { true }
+ 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" }
- expect(find('.js-version-status-badge', visible: false)).not_to be_visible
+ login_as :user
+ visit help_path
+ end
+
+ it 'should display custom help page text' do
+ expect(page).to have_text "My Custom Text"
+ end
+
+ it 'should hide marketing content when enabled' do
+ expect(page).not_to have_link "Get a support subscription"
+ end
+
+ it 'should use a custom support url' do
+ expect(page).to have_link "See our website for getting help", href: "http://example.com/help"
end
end
end
diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb
index bfe43bff10f..56c9b10e757 100644
--- a/spec/features/issuables/default_sort_order_spec.rb
+++ b/spec/features/issuables/default_sort_order_spec.rb
@@ -153,7 +153,9 @@ describe 'Projects > Issuables > Default sort order', feature: true do
context 'when the sort in the URL is id_desc' do
let(:issuable_type) { :issue }
- before { visit_issues(project, sort: 'id_desc') }
+ before do
+ visit_issues(project, sort: 'id_desc')
+ end
it 'shows the sort order as last created' do
expect(find('.issues-other-filters')).to have_content('Last created')
@@ -165,7 +167,9 @@ describe 'Projects > Issuables > Default sort order', feature: true do
context 'when the sort in the URL is id_asc' do
let(:issuable_type) { :issue }
- before { visit_issues(project, sort: 'id_asc') }
+ before do
+ visit_issues(project, sort: 'id_asc')
+ end
it 'shows the sort order as oldest created' do
expect(find('.issues-other-filters')).to have_content('Oldest created')
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index e5e4ba06b5a..863f8f75cd8 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -777,17 +777,17 @@ describe 'Filter issues', js: true, feature: true do
end
it 'open state' do
- find('.issues-state-filters a', text: 'Closed').click
+ find('.issues-state-filters [data-state="closed"]').click
wait_for_requests
- find('.issues-state-filters a', text: 'Open').click
+ find('.issues-state-filters [data-state="opened"]').click
wait_for_requests
expect(page).to have_selector('.issues-list .issue', count: 4)
end
it 'closed state' do
- find('.issues-state-filters a', text: 'Closed').click
+ find('.issues-state-filters [data-state="closed"]').click
wait_for_requests
expect(page).to have_selector('.issues-list .issue', count: 1)
@@ -795,7 +795,7 @@ describe 'Filter issues', js: true, feature: true do
end
it 'all state' do
- find('.issues-state-filters a', text: 'All').click
+ find('.issues-state-filters [data-state="all"]').click
wait_for_requests
expect(page).to have_selector('.issues-list .issue', count: 5)
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 8949dbcb663..96d37e33f3d 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -24,37 +24,17 @@ describe 'New/edit issue', :feature, :js do
visit new_namespace_project_issue_path(project.namespace, project)
end
- describe 'shorten users API pagination limit' do
+ describe 'shorten users API pagination limit (CE)' 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|
- has_multiple_assignees = *args[1]
-
- options = {
- toggle_class: 'js-user-search js-assignee-search js-multiselect js-save-user-data',
- title: 'Select assignee',
- filter: true,
- dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee',
- placeholder: 'Search users',
- data: {
- per_page: 1,
- null_user: true,
- current_user: true,
- project_id: project.try(:id),
- field_name: "issue[assignee_ids][]",
- default_label: 'Assignee',
- 'max-select': 1,
- 'dropdown-header': 'Assignee',
- multi_select: true,
- 'input-meta': 'name',
- 'always-show-selectbox': true
- }
- }
-
- if has_multiple_assignees
- options[:title] = 'Select assignee(s)'
- options[:data][:'dropdown-header'] = 'Assignee(s)'
- options[:data].delete(:'max-select')
- end
+ options = original_issue_dropdown_options.bind(original.receiver).call(*args)
+ options[:data][:per_page] = 2
options
end
@@ -74,6 +54,7 @@ describe 'New/edit issue', :feature, :js do
click_link user2.name
end
+ find('.js-assignee-search').click
find('.js-dropdown-input-clear').click
page.within '.dropdown-menu-user' do
@@ -83,7 +64,7 @@ describe 'New/edit issue', :feature, :js do
end
end
- describe 'single assignee' do
+ describe 'single assignee (CE)' do
before do
click_button 'Unassigned'
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
index 80f57906506..2c0a6ffd3cb 100644
--- a/spec/features/issues/note_polling_spec.rb
+++ b/spec/features/issues/note_polling_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
feature 'Issue notes polling', :feature, :js do
+ include NoteInteractionHelpers
+
let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) }
@@ -48,7 +50,7 @@ feature 'Issue notes polling', :feature, :js do
end
it 'when editing but have not changed anything, and an update comes in, show the updated content in the textarea' do
- find("#note_#{existing_note.id} .js-note-edit").click
+ click_edit_action(existing_note)
expect(page).to have_field("note[note]", with: note_text)
@@ -58,19 +60,18 @@ feature 'Issue notes polling', :feature, :js do
end
it 'when editing but you changed some things, and an update comes in, show a warning' do
- find("#note_#{existing_note.id} .js-note-edit").click
+ click_edit_action(existing_note)
expect(page).to have_field("note[note]", with: note_text)
find("#note_#{existing_note.id} .js-note-text").set('something random')
-
update_note(existing_note, updated_text)
expect(page).to have_selector(".alert")
end
it 'when editing but you changed some things, an update comes in, and you press cancel, show the updated content' do
- find("#note_#{existing_note.id} .js-note-edit").click
+ click_edit_action(existing_note)
expect(page).to have_field("note[note]", with: note_text)
@@ -128,4 +129,12 @@ feature 'Issue notes polling', :feature, :js do
note.update(note: new_text)
page.execute_script('notes.refresh();')
end
+
+ def click_edit_action(note)
+ note_element = find("#note_#{note.id}")
+
+ open_more_actions_dropdown(note)
+
+ note_element.find('.js-note-edit').click
+ end
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index eecc565d2bd..2cff53539f3 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -246,7 +246,10 @@ describe 'Issues', feature: true do
context 'with a filter on labels' do
let(:label) { create(:label, project: project) }
- before { create(:label_link, label: label, target: foo) }
+
+ before do
+ create(:label_link, label: label, target: foo)
+ end
it 'sorts by least recently due date by excluding nil due dates' do
bar.update(due_date: nil)
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index c82e8c03343..4763f454810 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -202,10 +202,12 @@ feature 'Login', feature: true do
# TODO: otp_grace_period_started_at
context 'global setting' do
- before(:each) { stub_application_setting(require_two_factor_authentication: true) }
+ before do
+ stub_application_setting(require_two_factor_authentication: true)
+ end
context 'with grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 48)
login_with(user)
end
@@ -242,7 +244,7 @@ feature 'Login', feature: true do
end
context 'without grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 0)
login_with(user)
end
@@ -265,7 +267,7 @@ feature 'Login', feature: true do
end
context 'with grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 48)
login_with(user)
end
@@ -306,7 +308,7 @@ feature 'Login', feature: true do
end
context 'without grace period defined' do
- before(:each) do
+ before do
stub_application_setting(two_factor_grace_period: 0)
login_with(user)
end
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index 27e2d5d16f3..9409c32104b 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -85,14 +85,18 @@ feature 'Merge request conflict resolution', js: true, feature: true do
context 'the conflicts are resolvable' do
let(:merge_request) { create_merge_request('conflict-resolvable') }
- before { visit namespace_project_merge_request_path(project.namespace, project, merge_request) }
+ before do
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
it 'shows a link to the conflict resolution page' do
expect(page).to have_link('conflicts', href: /\/conflicts\Z/)
end
context 'in Inline view mode' do
- before { click_link('conflicts', href: /\/conflicts\Z/) }
+ before do
+ click_link('conflicts', href: /\/conflicts\Z/)
+ end
include_examples "conflicts are resolved in Interactive mode"
include_examples "conflicts are resolved in Edit inline mode"
diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb
index bf34c99b92a..b4327743383 100644
--- a/spec/features/merge_requests/created_from_fork_spec.rb
+++ b/spec/features/merge_requests/created_from_fork_spec.rb
@@ -56,7 +56,7 @@ feature 'Merge request created from fork' do
visit_merge_request(merge_request)
page.within('.merge-request-tabs') { click_link 'Pipelines' }
- page.within('table.ci-table') do
+ page.within('.ci-table') do
expect(page).to have_content pipeline.status
expect(page).to have_content pipeline.id
end
diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb
index 854e2d1758f..e23dc2cd940 100644
--- a/spec/features/merge_requests/diff_notes_avatars_spec.rb
+++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
feature 'Diff note avatars', feature: true, js: true do
+ include NoteInteractionHelpers
+
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
@@ -110,6 +112,8 @@ feature 'Diff note avatars', feature: true, js: true do
end
it 'removes avatar when note is deleted' do
+ open_more_actions_dropdown(note)
+
page.within find(".note-row-#{note.id}") do
find('.js-note-delete').click
end
diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb
index 1e26b3d601e..d086be70d69 100644
--- a/spec/features/merge_requests/filter_merge_requests_spec.rb
+++ b/spec/features/merge_requests/filter_merge_requests_spec.rb
@@ -40,13 +40,13 @@ describe 'Filter merge requests', feature: true do
end
it 'does not change when closed link is clicked' do
- find('.issues-state-filters a', text: "Closed").click
+ find('.issues-state-filters [data-state="closed"]').click
expect_assignee_visual_tokens()
end
it 'does not change when all link is clicked' do
- find('.issues-state-filters a', text: "All").click
+ find('.issues-state-filters [data-state="all"]').click
expect_assignee_visual_tokens()
end
@@ -73,13 +73,13 @@ describe 'Filter merge requests', feature: true do
end
it 'does not change when closed link is clicked' do
- find('.issues-state-filters a', text: "Closed").click
+ find('.issues-state-filters [data-state="closed"]').click
expect_milestone_visual_tokens()
end
it 'does not change when all link is clicked' do
- find('.issues-state-filters a', text: "All").click
+ find('.issues-state-filters [data-state="all"]').click
expect_milestone_visual_tokens()
end
@@ -142,11 +142,9 @@ describe 'Filter merge requests', feature: true do
expect_tokens([{ name: 'assignee', value: "@#{user.username}" }])
expect_filtered_search_input_empty
- input_filtered_search_keys("label:~#{label.title} ")
+ input_filtered_search_keys("label:~#{label.title}")
expect_mr_list_count(1)
-
- find("#state-opened[href=\"#{URI.parse(current_url).path}?assignee_username=#{user.username}&label_name%5B%5D=#{label.title}&scope=all&state=opened\"]")
end
context 'assignee and label', js: true do
@@ -163,13 +161,13 @@ describe 'Filter merge requests', feature: true do
end
it 'does not change when closed link is clicked' do
- find('.issues-state-filters a', text: "Closed").click
+ find('.issues-state-filters [data-state="closed"]').click
expect_assignee_label_visual_tokens()
end
it 'does not change when all link is clicked' do
- find('.issues-state-filters a', text: "All").click
+ find('.issues-state-filters [data-state="all"]').click
expect_assignee_label_visual_tokens()
end
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 c1d4d508e57..836a7b6e09a 100644
--- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
+++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb
@@ -18,7 +18,9 @@ feature 'Merge immediately', :feature, :js do
sha: project.repository.commit('master').id)
end
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
context 'when there is active pipeline for merge request' do
background do
diff --git a/spec/features/merge_requests/mini_pipeline_graph_spec.rb b/spec/features/merge_requests/mini_pipeline_graph_spec.rb
index 3ceb91d951d..3a11ea3c8b2 100644
--- a/spec/features/merge_requests/mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_requests/mini_pipeline_graph_spec.rb
@@ -12,13 +12,39 @@ feature 'Mini Pipeline Graph', :js, :feature do
build.run
login_as(user)
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ visit_merge_request
+ end
+
+ def visit_merge_request(format = :html)
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request, format: format)
end
it 'should display a mini pipeline graph' do
expect(page).to have_selector('.mr-widget-pipeline-graph')
end
+ context 'as json' do
+ let(:artifacts_file1) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
+ let(:artifacts_file2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/png') }
+
+ before do
+ create(:ci_build, pipeline: pipeline, artifacts_file: artifacts_file1)
+ create(:ci_build, pipeline: pipeline, when: 'manual')
+ end
+
+ it 'avoids repeated database queries' do
+ before = ActiveRecord::QueryRecorder.new { visit_merge_request(:json) }
+
+ create(:ci_build, pipeline: pipeline, artifacts_file: artifacts_file2)
+ create(:ci_build, pipeline: pipeline, when: 'manual')
+
+ after = ActiveRecord::QueryRecorder.new { visit_merge_request(:json) }
+
+ expect(before.count).to eq(after.count)
+ expect(before.cached_count).to eq(after.cached_count)
+ end
+ end
+
describe 'build list toggle' do
let(:toggle) do
find('.mini-pipeline-graph-dropdown-toggle')
diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb
index 4c76004cb93..744bd484a80 100644
--- a/spec/features/merge_requests/pipelines_spec.rb
+++ b/spec/features/merge_requests/pipelines_spec.rb
@@ -28,7 +28,7 @@ feature 'Pipelines for Merge Requests', feature: true, js: true do
end
wait_for_requests
- expect(page).to have_selector('.pipeline-actions')
+ expect(page).to have_selector('.stage-cell')
end
end
diff --git a/spec/features/merge_requests/user_posts_notes_spec.rb b/spec/features/merge_requests/user_posts_notes_spec.rb
index 06de072257a..22552529b9e 100644
--- a/spec/features/merge_requests/user_posts_notes_spec.rb
+++ b/spec/features/merge_requests/user_posts_notes_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe 'Merge requests > User posts notes', :js do
+ include NoteInteractionHelpers
+
let(:project) { create(:project) }
let(:merge_request) do
create(:merge_request, source_project: project, target_project: project)
@@ -73,6 +75,8 @@ describe 'Merge requests > User posts notes', :js do
describe 'editing the note' do
before do
find('.note').hover
+ open_more_actions_dropdown(note)
+
find('.js-note-edit').click
end
@@ -100,6 +104,8 @@ describe 'Merge requests > User posts notes', :js do
wait_for_requests
find('.note').hover
+ open_more_actions_dropdown(note)
+
find('.js-note-edit').click
page.within('.current-note-edit-form') do
@@ -126,6 +132,8 @@ describe 'Merge requests > User posts notes', :js do
describe 'deleting an attachment' do
before do
find('.note').hover
+ open_more_actions_dropdown(note)
+
find('.js-note-edit').click
end
diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb
index b3dfd6d0e81..c8a4d23f695 100644
--- a/spec/features/milestones/milestones_spec.rb
+++ b/spec/features/milestones/milestones_spec.rb
@@ -37,6 +37,14 @@ describe 'Milestone draggable', feature: true, js: true do
expect(issue_target).to have_selector('.issuable-row')
end
+
+ it 'assigns issue when it has been dragged to ongoing list' do
+ login_as(:admin)
+ create_and_drag_issue
+
+ expect(@issue.reload.assignees).not_to be_empty
+ expect(page).to have_selector("#sortable_issue_#{@issue.iid} .assignee-icon img", count: 1)
+ end
end
context 'merge requests' do
@@ -72,7 +80,7 @@ describe 'Milestone draggable', feature: true, js: true do
end
def create_and_drag_issue(params = {})
- create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone))
+ @issue = create(:issue, params.merge(title: 'Foo', project: project, milestone: milestone))
visit namespace_project_milestone_path(project.namespace, project, milestone)
scroll_into_view('.milestone-content')
diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb
index 05a7587f8d4..89868c737f7 100644
--- a/spec/features/profiles/account_spec.rb
+++ b/spec/features/profiles/account_spec.rb
@@ -31,8 +31,13 @@ feature 'Profile > Account', feature: true do
given(:new_project_path) { "/#{new_username}/#{project.path}" }
given(:old_project_path) { "/#{user.username}/#{project.path}" }
- before(:context) { TestEnv.clean_test_path }
- after(:example) { TestEnv.clean_test_path }
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
scenario 'the project is accessible via the new path' do
update_username(new_username)
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index 27a20e78a43..7e2e685df26 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -17,6 +17,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
def disallow_personal_access_token_saves!
allow_any_instance_of(PersonalAccessToken).to receive(:save).and_return(false)
+
errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") }
allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors)
end
@@ -91,8 +92,11 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
context "when revocation fails" do
it "displays an error message" do
- disallow_personal_access_token_saves!
visit profile_personal_access_tokens_path
+ allow_any_instance_of(PersonalAccessToken).to receive(:update!).and_return(false)
+
+ errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") }
+ allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors)
click_on "Revoke"
expect(active_personal_access_tokens).to have_text(personal_access_token.name)
diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb
index 25c4f3c87a2..860373e531b 100644
--- a/spec/features/projects/artifacts/file_spec.rb
+++ b/spec/features/projects/artifacts/file_spec.rb
@@ -39,6 +39,7 @@ feature 'Artifact file', :js, feature: true do
context 'JPG file' do
before do
+ page.driver.browser.url_blacklist = []
visit_file('rails_sample.jpg')
wait_for_requests
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 82cfbfda157..71ffa352f80 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
feature 'File blob', :js, feature: true do
let(:project) { create(:project, :public) }
- def visit_blob(path, fragment = nil)
- visit namespace_project_blob_path(project.namespace, project, File.join('master', path), anchor: fragment)
+ def visit_blob(path, anchor: nil, ref: 'master')
+ visit namespace_project_blob_path(project.namespace, project, File.join(ref, path), anchor: anchor)
wait_for_requests
end
@@ -17,6 +17,7 @@ feature 'File blob', :js, feature: true do
it 'displays the blob' do
aggregate_failures do
# shows highlighted Ruby code
+ expect(page).to have_css(".js-syntax-highlight")
expect(page).to have_content("require 'fileutils'")
# does not show a viewer switcher
@@ -71,6 +72,7 @@ feature 'File blob', :js, feature: true do
expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
@@ -101,7 +103,7 @@ feature 'File blob', :js, feature: true do
context 'visiting with a line number anchor' do
before do
- visit_blob('files/markdown/ruby-style-guide.md', 'L1')
+ visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
it 'displays the blob using the simple viewer' do
@@ -114,6 +116,7 @@ feature 'File blob', :js, feature: true do
expect(page).to have_selector('#LC1.hll')
# shows highlighted Markdown code
+ expect(page).to have_css(".js-syntax-highlight")
expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
@@ -352,6 +355,37 @@ feature 'File blob', :js, feature: true do
end
end
+ context 'binary file that appears to be text in the first 1024 bytes' do
+ before do
+ visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows a download link
+ expect(page).to have_link('Download (23.8 KB)')
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # The specs below verify an arguably incorrect result, but since we only
+ # learn that the file is not actually text once the text viewer content
+ # is loaded asynchronously, there is no straightforward way to get these
+ # synchronously loaded elements to display correctly.
+ #
+ # Clicking the copy button will result in nothing being copied.
+ # Clicking the raw button will result in the binary file being downloaded,
+ # as expected.
+
+ # shows an enabled copy button, incorrectly
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button, incorrectly
+ expect(page).to have_link('Open raw')
+ end
+ end
+ end
+
context '.gitlab-ci.yml' do
before do
project.add_master(project.creator)
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index 1a38997450d..d04c3248ead 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -102,7 +102,7 @@ feature 'Editing file blob', feature: true, js: true do
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(find('.js-target-branch .dropdown-toggle-text').text).to eq(branch)
+ expect(find('.js-branch-name').value).to eq(branch)
end
end
@@ -112,7 +112,7 @@ feature 'Editing file blob', feature: true, js: true do
end
it 'shows blob editor with patch branch' do
- expect(find('.js-target-branch .dropdown-toggle-text').text).to eq('patch-1')
+ expect(find('.js-branch-name').value).to eq('patch-1')
end
end
end
@@ -128,7 +128,7 @@ feature 'Editing file blob', feature: true, js: true do
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(find('.js-target-branch .dropdown-toggle-text').text).to eq(branch)
+ expect(find('.js-branch-name').value).to eq(branch)
end
end
end
diff --git a/spec/features/projects/blobs/user_create_spec.rb b/spec/features/projects/blobs/user_create_spec.rb
deleted file mode 100644
index 4b6c55f5f44..00000000000
--- a/spec/features/projects/blobs/user_create_spec.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-require 'spec_helper'
-
-feature 'New blob creation', feature: true, js: true do
- include TargetBranchHelpers
-
- given(:user) { create(:user) }
- given(:role) { :developer }
- given(:project) { create(:project) }
- given(:content) { 'class NextFeature\nend\n' }
-
- background do
- login_as(user)
- project.team << [user, role]
- visit namespace_project_new_blob_path(project.namespace, project, 'master')
- end
-
- def edit_file
- wait_for_requests
- fill_in 'file_name', with: 'feature.rb'
- execute_script("ace.edit('editor').setValue('#{content}')")
- end
-
- def commit_file
- click_button 'Commit changes'
- end
-
- context 'with default target branch' do
- background do
- edit_file
- commit_file
- end
-
- scenario 'creates the blob in the default branch' do
- expect(page).to have_content 'master'
- expect(page).to have_content 'successfully created'
- expect(page).to have_content 'NextFeature'
- end
- end
-
- context 'with different target branch' do
- background do
- edit_file
- select_branch('feature')
- commit_file
- end
-
- scenario 'creates the blob in the different branch' do
- expect(page).to have_content 'feature'
- expect(page).to have_content 'successfully created'
- end
- end
-
- context 'with a new target branch' do
- given(:new_branch_name) { 'new-feature' }
-
- background do
- edit_file
- create_new_branch(new_branch_name)
- commit_file
- end
-
- scenario 'creates the blob in the new branch' do
- expect(page).to have_content new_branch_name
- expect(page).to have_content 'successfully created'
- end
- scenario 'returns you to the mr' 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 file'
- end
- end
-
- context 'the file already exist in the source branch' do
- background do
- Files::CreateService.new(
- project,
- user,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: 'Create file',
- file_path: 'feature.rb',
- file_content: content
- ).execute
- edit_file
- commit_file
- end
-
- scenario 'shows error message' do
- expect(page).to have_content('A file with this name already exists')
- expect(page).to have_content('New file')
- expect(page).to have_content('NextFeature')
- end
- end
-end
diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb
new file mode 100644
index 00000000000..48b7f1e0f34
--- /dev/null
+++ b/spec/features/projects/diffs/diff_show_spec.rb
@@ -0,0 +1,133 @@
+require 'spec_helper'
+
+feature 'Diff file viewer', :js, feature: true do
+ let(:project) { create(:project, :public, :repository) }
+
+ def visit_commit(sha, anchor: nil)
+ visit namespace_project_commit_path(project.namespace, project, sha, anchor: anchor)
+
+ wait_for_requests
+ end
+
+ context 'Ruby file' do
+ before do
+ visit_commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
+ end
+
+ it 'shows highlighted Ruby code' do
+ within('.diff-file[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd"]') do
+ expect(page).to have_css(".js-syntax-highlight")
+ expect(page).to have_content("def popen(cmd, path=nil)")
+ end
+ end
+ end
+
+ context 'Ruby file (stored in LFS)' do
+ before do
+ project.add_master(project.creator)
+
+ @commit_id = Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add Ruby file in LFS",
+ file_path: 'files/lfs/ruby.rb',
+ file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data
+ ).execute[:result]
+ end
+
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+
+ visit_commit(@commit_id)
+ end
+
+ it 'shows an error message' do
+ expect(page).to have_content('This source diff could not be displayed because it is stored in LFS. You can view the blob instead.')
+ end
+ end
+
+ context 'when LFS is disabled on the project' do
+ before do
+ visit_commit(@commit_id)
+ end
+
+ it 'displays the diff' do
+ expect(page).to have_content('size 1575078')
+ end
+ end
+ end
+
+ context 'Image file' do
+ before do
+ visit_commit('2f63565e7aac07bcdadb654e253078b727143ec4')
+ end
+
+ it 'shows a rendered image' do
+ within('.diff-file[id="e986451b8f7397b617dbb6fffcb5539328c56921"]') do
+ expect(page).to have_css('img[alt="files/images/6049019_460s.jpg"]')
+ end
+ end
+ end
+
+ context 'ISO file (stored in LFS)' do
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+
+ visit_commit('048721d90c449b244b7b4c53a9186b04330174ec')
+ end
+
+ it 'shows that file was added' do
+ expect(page).to have_content('File added')
+ end
+ end
+
+ context 'when LFS is disabled on the project' do
+ before do
+ visit_commit('048721d90c449b244b7b4c53a9186b04330174ec')
+ end
+
+ it 'displays the diff' do
+ expect(page).to have_content('size 1575078')
+ end
+ end
+ end
+
+ context 'ZIP file' do
+ before do
+ visit_commit('ae73cb07c9eeaf35924a10f713b364d32b2dd34f')
+ end
+
+ it 'shows that file was added' do
+ expect(page).to have_content('File added')
+ end
+ end
+
+ context 'binary file that appears to be text in the first 1024 bytes' do
+ before do
+ visit_commit('7b1cf4336b528e0f3d1d140ee50cafdbc703597c')
+ end
+
+ it 'shows the diff is collapsed' do
+ expect(page).to have_content('This diff is collapsed. Click to expand it.')
+ end
+
+ context 'expanding the diff' do
+ before do
+ # We can't use `click_link` because the "link" doesn't have an `href`.
+ find('a.click-to-expand').click
+
+ wait_for_requests
+ end
+
+ it 'shows there is no preview' do
+ expect(page).to have_content('No preview for this file type')
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index c49648f54bd..d76b5e4ef1b 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -68,9 +68,12 @@ describe 'Edit Project Settings', feature: true do
end
describe 'project features visibility pages' do
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+ let(:job) { create(:ci_build, pipeline: pipeline) }
+
let(:tools) do
{
- builds: namespace_project_pipelines_path(project.namespace, project),
+ 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),
diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb
index 4e5682c8636..1b680a56492 100644
--- a/spec/features/projects/group_links_spec.rb
+++ b/spec/features/projects/group_links_spec.rb
@@ -16,15 +16,17 @@ feature 'Project group links', :feature, :js do
before do
visit namespace_project_settings_members_path(project.namespace, project)
+ click_on 'share-with-group-tab'
+
select2 group.id, from: '#link_group_id'
fill_in 'expires_at_groups', with: (Time.current + 4.5.days).strftime('%Y-%m-%d')
page.find('body').click
- click_on 'Share'
+ find('.btn-create').trigger('click')
end
it 'shows the expiration time with a warning class' do
- page.within('.enabled-groups') do
- expect(page).to have_content('expires in 4 days')
+ page.within('.project-members-groups') do
+ expect(page).to have_content('Expires in 4 days')
expect(page).to have_selector('.text-warning')
end
end
@@ -43,6 +45,7 @@ feature 'Project group links', :feature, :js do
it 'does not show ancestors', :nested_groups do
visit namespace_project_settings_members_path(project.namespace, project)
+ click_on 'share-with-group-tab'
click_link 'Search for a group'
page.within '.select2-drop' do
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 0eda46649db..31c93c75d25 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -5,10 +5,11 @@ feature 'Jobs', :feature do
let(:user) { create(:user) }
let(:user_access_level) { :developer }
let(:project) { create(:project) }
+ let(:namespace) { project.namespace }
let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
- let(:build2) { create(:ci_build) }
+ let(:job) { create(:ci_build, :trace, pipeline: pipeline) }
+ let(:job2) { create(:ci_build) }
let(:artifacts_file) do
fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')
@@ -20,7 +21,7 @@ feature 'Jobs', :feature do
end
describe "GET /:project/jobs" do
- let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
context "Pending scope" do
before do
@@ -30,30 +31,30 @@ feature 'Jobs', :feature do
it "shows Pending tab jobs" do
expect(page).to have_link 'Cancel running'
expect(page).to have_selector('.nav-links li.active', text: 'Pending')
- expect(page).to have_content build.short_sha
- expect(page).to have_content build.ref
- expect(page).to have_content build.name
+ expect(page).to have_content job.short_sha
+ expect(page).to have_content job.ref
+ expect(page).to have_content job.name
end
end
context "Running scope" do
before do
- build.run!
+ job.run!
visit namespace_project_jobs_path(project.namespace, project, scope: :running)
end
it "shows Running tab jobs" do
expect(page).to have_selector('.nav-links li.active', text: 'Running')
expect(page).to have_link 'Cancel running'
- expect(page).to have_content build.short_sha
- expect(page).to have_content build.ref
- expect(page).to have_content build.name
+ expect(page).to have_content job.short_sha
+ expect(page).to have_content job.ref
+ expect(page).to have_content job.name
end
end
context "Finished scope" do
before do
- build.run!
+ job.run!
visit namespace_project_jobs_path(project.namespace, project, scope: :finished)
end
@@ -72,9 +73,9 @@ feature 'Jobs', :feature do
it "shows All tab jobs" do
expect(page).to have_selector('.nav-links li.active', text: 'All')
- expect(page).to have_content build.short_sha
- expect(page).to have_content build.ref
- expect(page).to have_content build.name
+ expect(page).to have_content job.short_sha
+ expect(page).to have_content job.ref
+ expect(page).to have_content job.name
expect(page).not_to have_link 'Cancel running'
end
end
@@ -96,7 +97,7 @@ feature 'Jobs', :feature do
describe "POST /:project/jobs/:id/cancel_all" do
before do
- build.run!
+ job.run!
visit namespace_project_jobs_path(project.namespace, project)
click_link "Cancel running"
end
@@ -104,17 +105,23 @@ feature 'Jobs', :feature do
it 'shows all necessary content' do
expect(page).to have_selector('.nav-links li.active', text: 'All')
expect(page).to have_content 'canceled'
- expect(page).to have_content build.short_sha
- expect(page).to have_content build.ref
- expect(page).to have_content build.name
+ expect(page).to have_content job.short_sha
+ expect(page).to have_content job.ref
+ expect(page).to have_content job.name
expect(page).not_to have_link 'Cancel running'
end
end
describe "GET /:project/jobs/:id" do
context "Job from project" do
+ let(:job) { create(:ci_build, :success, pipeline: pipeline) }
+
before do
- visit namespace_project_job_path(project.namespace, project, build)
+ visit namespace_project_job_path(project.namespace, project, job)
+ end
+
+ it 'shows status name', :js do
+ expect(page).to have_css('.ci-status.ci-success', text: 'passed')
end
it 'shows commit`s data' do
@@ -124,14 +131,56 @@ feature 'Jobs', :feature do
expect(page).to have_content pipeline.git_author_name
end
- it 'shows active build' do
+ it 'shows active job' do
expect(page).to have_selector('.build-job.active')
end
end
+ context 'when job is not running', :js do
+ let(:job) { create(:ci_build, :success, pipeline: pipeline) }
+
+ before do
+ visit namespace_project_job_path(project.namespace, project, job)
+ end
+
+ it 'shows retry button' do
+ expect(page).to have_link('Retry')
+ end
+
+ context 'if job passed' do
+ it 'does not show New issue button' do
+ expect(page).not_to have_link('New issue')
+ end
+ end
+
+ context 'if job failed' do
+ let(:job) { create(:ci_build, :failed, pipeline: pipeline) }
+
+ before do
+ visit namespace_project_job_path(namespace, project, job)
+ end
+
+ it 'shows New issue button' do
+ expect(page).to have_link('New issue')
+ end
+
+ 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)
+ options = { issue: { title: button_title, description: job_path } }
+
+ href = new_namespace_project_issue_path(namespace, project, options)
+
+ page.within('.header-action-buttons') do
+ expect(find('.js-new-issue')['href']).to include(href)
+ end
+ end
+ end
+ end
+
context "Job from other project" do
before do
- visit namespace_project_job_path(project.namespace, project, build2)
+ visit namespace_project_job_path(project.namespace, project, job2)
end
it { expect(page.status_code).to eq(404) }
@@ -139,8 +188,8 @@ feature 'Jobs', :feature do
context "Download artifacts" do
before do
- build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_job_path(project.namespace, project, build)
+ job.update_attributes(artifacts_file: artifacts_file)
+ visit namespace_project_job_path(project.namespace, project, job)
end
it 'has button to download artifacts' do
@@ -150,10 +199,10 @@ feature 'Jobs', :feature do
context 'Artifacts expire date' do
before do
- build.update_attributes(artifacts_file: artifacts_file,
- artifacts_expire_at: expire_at)
+ job.update_attributes(artifacts_file: artifacts_file,
+ artifacts_expire_at: expire_at)
- visit namespace_project_job_path(project.namespace, project, build)
+ visit namespace_project_job_path(project.namespace, project, job)
end
context 'no expire date defined' do
@@ -199,7 +248,7 @@ feature 'Jobs', :feature do
context "when visiting old URL" do
let(:job_url) do
- namespace_project_job_path(project.namespace, project, build)
+ namespace_project_job_path(project.namespace, project, job)
end
before do
@@ -213,9 +262,9 @@ feature 'Jobs', :feature do
feature 'Raw trace' do
before do
- build.run!
+ job.run!
- visit namespace_project_job_path(project.namespace, project, build)
+ visit namespace_project_job_path(project.namespace, project, job)
end
it do
@@ -225,16 +274,16 @@ feature 'Jobs', :feature do
feature 'HTML trace', :js do
before do
- build.run!
+ job.run!
- visit namespace_project_job_path(project.namespace, project, build)
+ visit namespace_project_job_path(project.namespace, project, job)
end
context 'when job has an initial trace' do
it 'loads job trace' do
expect(page).to have_content 'BUILD TRACE'
- build.trace.write do |stream|
+ job.trace.write do |stream|
stream.append(' and more trace', 11)
end
@@ -246,12 +295,12 @@ feature 'Jobs', :feature do
feature 'Variables' do
let(:trigger_request) { create(:ci_trigger_request_with_variables) }
- let(:build) do
+ let(:job) do
create :ci_build, pipeline: pipeline, trigger_request: trigger_request
end
before do
- visit namespace_project_job_path(project.namespace, project, build)
+ visit namespace_project_job_path(project.namespace, project, job)
end
it 'shows variable key and value after click', js: true do
@@ -273,20 +322,20 @@ feature 'Jobs', :feature do
context 'job is successfull and has deployment' do
let(:deployment) { create(:deployment) }
- let(:build) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) }
+ 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, build)
+ visit namespace_project_job_path(project.namespace, project, job)
expect(page).to have_link environment.name
end
end
context 'job is complete and not successful' do
- let(:build) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) }
+ 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, build)
+ visit namespace_project_job_path(project.namespace, project, job)
expect(page).to have_link environment.name
end
@@ -294,10 +343,10 @@ feature 'Jobs', :feature do
context 'job creates a new deployment' do
let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) }
- let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
+ 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, build)
+ visit namespace_project_job_path(project.namespace, project, job)
expect(page).to have_link('latest deployment')
end
@@ -305,72 +354,47 @@ feature 'Jobs', :feature do
end
end
- describe "POST /:project/jobs/:id/cancel" do
+ describe "POST /:project/jobs/:id/cancel", :js do
context "Job from project" do
before do
- build.run!
- visit namespace_project_job_path(project.namespace, project, build)
- click_link "Cancel"
+ job.run!
+ visit namespace_project_job_path(project.namespace, project, job)
+ find('.js-cancel-job').click()
end
it 'loads the page and shows all needed controls' do
expect(page.status_code).to eq(200)
- expect(page).to have_content 'canceled'
expect(page).to have_content 'Retry'
end
end
-
- context "Job from other project" do
- before do
- build.run!
- visit namespace_project_job_path(project.namespace, project, build)
- page.driver.post(cancel_namespace_project_job_path(project.namespace, project, build2))
- end
-
- it { expect(page.status_code).to eq(404) }
- end
end
describe "POST /:project/jobs/:id/retry" do
- context "Job from project" do
+ context "Job from project", :js do
before do
- build.run!
- visit namespace_project_job_path(project.namespace, project, build)
- click_link 'Cancel'
- page.within('.build-header') do
- click_link 'Retry job'
- end
+ job.run!
+ visit namespace_project_job_path(project.namespace, project, job)
+ find('.js-cancel-job').click()
+ find('.js-retry-button').trigger('click')
end
- it 'shows the right status and buttons' do
+ it 'shows the right status and buttons', :js do
expect(page).to have_http_status(200)
- expect(page).to have_content 'pending'
page.within('aside.right-sidebar') do
expect(page).to have_content 'Cancel'
end
end
end
- context "Job from other project" do
- before do
- build.run!
- visit namespace_project_job_path(project.namespace, project, build)
- click_link 'Cancel'
- page.driver.post(retry_namespace_project_job_path(project.namespace, project, build2))
- end
-
- it { expect(page).to have_http_status(404) }
- end
-
context "Job that current user is not allowed to retry" do
before do
- build.run!
- build.cancel!
+ job.run!
+ job.cancel!
project.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
logout_direct
login_with(create(:user))
- visit namespace_project_job_path(project.namespace, project, build)
+ visit namespace_project_job_path(project.namespace, project, job)
end
it 'does not show the Retry button' do
@@ -383,15 +407,15 @@ feature 'Jobs', :feature do
describe "GET /:project/jobs/:id/download" do
before do
- build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_job_path(project.namespace, project, build)
+ job.update_attributes(artifacts_file: artifacts_file)
+ visit namespace_project_job_path(project.namespace, project, job)
click_link 'Download'
end
context "Build from other project" do
before do
- build2.update_attributes(artifacts_file: artifacts_file)
- visit download_namespace_project_job_artifacts_path(project.namespace, project, build2)
+ job2.update_attributes(artifacts_file: artifacts_file)
+ visit download_namespace_project_job_artifacts_path(project.namespace, project, job2)
end
it { expect(page.status_code).to eq(404) }
@@ -403,23 +427,23 @@ feature 'Jobs', :feature do
context 'job from project' do
before do
Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' }
- build.run!
- visit namespace_project_job_path(project.namespace, project, build)
+ job.run!
+ visit namespace_project_job_path(project.namespace, project, job)
find('.js-raw-link-controller').click()
end
it 'sends the right headers' do
expect(page.status_code).to eq(200)
expect(page.response_headers['Content-Type']).to eq('text/plain; charset=utf-8')
- expect(page.response_headers['X-Sendfile']).to eq(build.trace.send(:current_path))
+ expect(page.response_headers['X-Sendfile']).to eq(job.trace.send(:current_path))
end
end
context 'job from other project' do
before do
Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' }
- build2.run!
- visit raw_namespace_project_job_path(project.namespace, project, build2)
+ job2.run!
+ visit raw_namespace_project_job_path(project.namespace, project, job2)
end
it 'sends the right headers' do
@@ -434,21 +458,18 @@ feature 'Jobs', :feature do
before do
Capybara.current_session.driver.headers = { 'X-Sendfile-Type' => 'X-Sendfile' }
- build.run!
-
- allow_any_instance_of(Gitlab::Ci::Trace).to receive(:paths)
- .and_return(paths)
-
- visit namespace_project_job_path(project.namespace, project, build)
+ job.run!
end
- context 'when build has trace in file', :js do
- let(:paths) do
- [existing_file]
- end
-
+ context 'when job has trace in file', :js do
before do
- find('.js-raw-link-controller').click()
+ allow_any_instance_of(Gitlab::Ci::Trace)
+ .to receive(:paths)
+ .and_return([existing_file])
+
+ visit namespace_project_job_path(namespace, project, job)
+
+ find('.js-raw-link-controller').click
end
it 'sends the right headers' do
@@ -458,18 +479,24 @@ feature 'Jobs', :feature do
end
end
- context 'when job has trace in DB' do
- let(:paths) { [] }
+ context 'when job has trace in the database', :js do
+ before do
+ allow_any_instance_of(Gitlab::Ci::Trace)
+ .to receive(:paths)
+ .and_return([])
+
+ visit namespace_project_job_path(namespace, project, job)
+ end
it 'sends the right headers' do
- expect(page.status_code).not_to have_selector('.js-raw-link-controller')
+ expect(page).not_to have_selector('.js-raw-link-controller')
end
end
end
context "when visiting old URL" do
let(:raw_job_url) do
- raw_namespace_project_job_path(project.namespace, project, build)
+ raw_namespace_project_job_path(project.namespace, project, job)
end
before do
@@ -485,7 +512,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, build, format: :json)
+ visit trace_namespace_project_job_path(project.namespace, project, job, format: :json)
end
it { expect(page.status_code).to eq(200) }
@@ -493,7 +520,7 @@ feature 'Jobs', :feature do
context "Job from other project" do
before do
- visit trace_namespace_project_job_path(project.namespace, project, build2, format: :json)
+ visit trace_namespace_project_job_path(project.namespace, project, job2, format: :json)
end
it { expect(page.status_code).to eq(404) }
@@ -503,7 +530,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, build)
+ visit status_namespace_project_job_path(project.namespace, project, job)
end
it { expect(page.status_code).to eq(200) }
@@ -511,7 +538,7 @@ feature 'Jobs', :feature do
context "Job from other project" do
before do
- visit status_namespace_project_job_path(project.namespace, project, build2)
+ visit status_namespace_project_job_path(project.namespace, project, job2)
end
it { expect(page.status_code).to eq(404) }
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index c66b9a34b86..b1f9eb15667 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -17,10 +17,10 @@ feature "New project", feature: true do
expect(find_field("project_visibility_level_#{level}")).to be_checked
end
- it 'saves visibility level on validation error' do
+ it "saves visibility level #{level} on validation error" do
visit new_project_path
- choose(key)
+ choose(s_(key))
click_button('Create project')
expect(find_field("project_visibility_level_#{level}")).to be_checked
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 317949d6b56..2d43f7a10bc 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -127,7 +127,7 @@ feature 'Pipeline Schedules', :feature do
end
it 'shows the pipeline schedule with default ref' do
- page.within('.git-revision-dropdown-toggle') do
+ page.within('.js-target-branch-dropdown') do
expect(first('.dropdown-toggle-text').text).to eq('master')
end
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 36a3ddca6ef..12c5ad45baf 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -47,7 +47,9 @@ describe 'Pipeline', :feature, :js do
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
- before { visit namespace_project_pipeline_path(project.namespace, project, pipeline) }
+ before do
+ visit namespace_project_pipeline_path(project.namespace, project, pipeline)
+ end
it 'shows the pipeline graph' do
expect(page).to have_selector('.pipeline-visualization')
@@ -164,7 +166,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_content('retried') }
context 'when retrying' do
- before { find('.js-retry-button').trigger('click') }
+ before do
+ find('.js-retry-button').trigger('click')
+ end
it { expect(page).not_to have_content('Retry') }
end
@@ -174,7 +178,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
- before { click_on 'Cancel running' }
+ before do
+ click_on 'Cancel running'
+ end
it { expect(page).not_to have_content('Cancel running') }
end
@@ -226,7 +232,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_content('retried') }
context 'when retrying' do
- before { find('.js-retry-button').trigger('click') }
+ before do
+ find('.js-retry-button').trigger('click')
+ end
it { expect(page).not_to have_content('Retry') }
end
@@ -236,7 +244,9 @@ describe 'Pipeline', :feature, :js do
it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
- before { click_on 'Cancel running' }
+ before do
+ click_on 'Cancel running'
+ end
it { expect(page).not_to have_content('Cancel running') }
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 05c2bf350f1..db2d1a100a5 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -149,7 +149,9 @@ describe 'Pipelines', :feature, :js do
create(:ci_pipeline, :invalid, project: project)
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'contains badge that indicates errors' do
expect(page).to have_content 'yaml invalid'
@@ -171,10 +173,12 @@ describe 'Pipelines', :feature, :js do
commands: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'has a dropdown with play button' do
- expect(page).to have_selector('.dropdown-toggle.btn.btn-default .icon-play')
+ expect(page).to have_selector('.dropdown-new.btn.btn-default .icon-play')
end
it 'has link to the manual action' do
@@ -204,7 +208,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'is cancelable' do
expect(page).to have_selector('.js-pipelines-cancel-button')
@@ -215,7 +221,9 @@ describe 'Pipelines', :feature, :js do
end
context 'when canceling' do
- before { find('.js-pipelines-cancel-button').trigger('click') }
+ before do
+ find('.js-pipelines-cancel-button').trigger('click')
+ end
it 'indicates that pipeline was canceled' do
expect(page).not_to have_selector('.js-pipelines-cancel-button')
@@ -255,7 +263,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'has artifats' do
expect(page).to have_selector('.build-artifacts')
@@ -284,7 +294,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it { expect(page).not_to have_selector('.build-artifacts') }
end
@@ -297,7 +309,9 @@ describe 'Pipelines', :feature, :js do
stage: 'test')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it { expect(page).not_to have_selector('.build-artifacts') }
end
@@ -310,7 +324,9 @@ describe 'Pipelines', :feature, :js do
name: 'build')
end
- before { visit_project_pipelines }
+ before do
+ visit_project_pipelines
+ end
it 'should render a mini pipeline graph' do
expect(page).to have_selector('.js-mini-pipeline-graph')
@@ -437,7 +453,9 @@ describe 'Pipelines', :feature, :js do
end
context 'with gitlab-ci.yml' do
- before { stub_ci_pipeline_to_return_yaml_file }
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
it 'creates a new pipeline' do
expect { click_on 'Create pipeline' }
@@ -448,7 +466,9 @@ describe 'Pipelines', :feature, :js do
end
context 'without gitlab-ci.yml' do
- before { click_on 'Create pipeline' }
+ before do
+ click_on 'Create pipeline'
+ end
it { expect(page).to have_content('Missing .gitlab-ci.yml file') }
end
diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb
index 11dcab4d737..2a9b32ea07e 100644
--- a/spec/features/projects/project_settings_spec.rb
+++ b/spec/features/projects/project_settings_spec.rb
@@ -58,8 +58,13 @@ describe 'Edit Project Settings', feature: true do
# Not using empty project because we need a repo to exist
let(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') }
- before(:context) { TestEnv.clean_test_path }
- after(:example) { TestEnv.clean_test_path }
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
specify 'the project is accessible via the new path' do
rename_project(project, path: 'bar')
@@ -96,9 +101,17 @@ describe 'Edit Project Settings', feature: true do
let!(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') }
let!(:group) { create(:group) }
- before(:context) { TestEnv.clean_test_path }
- before(:example) { group.add_owner(user) }
- after(:example) { TestEnv.clean_test_path }
+ before(:context) do
+ TestEnv.clean_test_path
+ end
+
+ before(:example) do
+ group.add_owner(user)
+ end
+
+ after(:example) do
+ TestEnv.clean_test_path
+ end
specify 'the project is accessible via the new path' do
transfer_project(project, group)
diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb
new file mode 100644
index 00000000000..4cc38c5286e
--- /dev/null
+++ b/spec/features/projects/settings/repository_settings_spec.rb
@@ -0,0 +1,78 @@
+require 'spec_helper'
+
+feature 'Repository settings', feature: true do
+ let(:project) { create(:project_empty_repo) }
+ let(:user) { create(:user) }
+ let(:role) { :developer }
+
+ background do
+ project.team << [user, role]
+ login_as(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)
+
+ expect(page.status_code).to eq(404)
+ end
+ end
+
+ context 'for master' do
+ given(:role) { :master }
+
+ context 'Deploy Keys', js: true do
+ let(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) }
+ let(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) }
+ let(:new_ssh_key) { attributes_for(:key)[:key] }
+
+ scenario 'get list of keys' do
+ project.deploy_keys << private_deploy_key
+ project.deploy_keys << public_deploy_key
+
+ visit namespace_project_settings_repository_path(project.namespace, project)
+
+ expect(page.status_code).to eq(200)
+ expect(page).to have_content('private_deploy_key')
+ expect(page).to have_content('public_deploy_key')
+ end
+
+ scenario 'add a new deploy key' do
+ visit namespace_project_settings_repository_path(project.namespace, project)
+
+ fill_in 'deploy_key_title', with: 'new_deploy_key'
+ fill_in 'deploy_key_key', with: new_ssh_key
+ check 'deploy_key_can_push'
+ click_button 'Add key'
+
+ expect(page).to have_content('new_deploy_key')
+ expect(page).to have_content('Write access allowed')
+ end
+
+ scenario 'edit an existing deploy key' do
+ project.deploy_keys << private_deploy_key
+ visit namespace_project_settings_repository_path(project.namespace, project)
+
+ find('li', text: private_deploy_key.title).click_link('Edit')
+
+ fill_in 'deploy_key_title', with: 'updated_deploy_key'
+ check 'deploy_key_can_push'
+ click_button 'Save changes'
+
+ expect(page).to have_content('updated_deploy_key')
+ expect(page).to have_content('Write access allowed')
+ end
+
+ scenario 'remove an existing deploy key' do
+ project.deploy_keys << private_deploy_key
+ visit namespace_project_settings_repository_path(project.namespace, project)
+
+ find('li', text: private_deploy_key.title).click_button('Remove')
+
+ expect(page).not_to have_content(private_deploy_key.title)
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
new file mode 100644
index 00000000000..5ac1ca45c74
--- /dev/null
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -0,0 +1,86 @@
+require 'rails_helper'
+
+feature 'Create Snippet', :js, feature: true do
+ include DropzoneHelper
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository, :public) }
+
+ def fill_form
+ fill_in 'project_snippet_title', with: 'My Snippet Title'
+ fill_in 'project_snippet_description', with: 'My Snippet **Description**'
+ page.within('.file-editor') do
+ find('.ace_editor').native.send_keys('Hello World!')
+ end
+ end
+
+ context 'when a user is authenticated' do
+ before do
+ project.team << [user, :master]
+ login_as(user)
+
+ visit namespace_project_snippets_path(project.namespace, project)
+
+ click_on('New snippet')
+ end
+
+ it 'creates a new snippet' do
+ fill_form
+ click_button('Create snippet')
+ wait_for_requests
+
+ expect(page).to have_content('My Snippet Title')
+ expect(page).to have_content('Hello World!')
+ page.within('.snippet-header .description') do
+ expect(page).to have_content('My Snippet Description')
+ expect(page).to have_selector('strong')
+ end
+ end
+
+ it 'uploads a file when dragging into textarea' do
+ fill_form
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+
+ expect(page.find_field("project_snippet_description").value).to have_content('banana_sample')
+
+ click_button('Create snippet')
+ wait_for_requests
+
+ link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/#{Regexp.escape(project.full_path) }/uploads/\h{32}/banana_sample\.gif\z})
+ end
+
+ it 'creates a snippet when all reuiqred fields are filled in after validation failing' do
+ fill_in 'project_snippet_title', with: 'My Snippet Title'
+ click_button('Create snippet')
+
+ expect(page).to have_selector('#error_explanation')
+
+ fill_form
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+
+ click_button('Create snippet')
+ wait_for_requests
+
+ expect(page).to have_content('My Snippet Title')
+ expect(page).to have_content('Hello World!')
+ page.within('.snippet-header .description') do
+ expect(page).to have_content('My Snippet Description')
+ expect(page).to have_selector('strong')
+ end
+ link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/#{Regexp.escape(project.full_path) }/uploads/\h{32}/banana_sample\.gif\z})
+ end
+ end
+
+ context 'when a user is not authenticated' 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)
+
+ expect(page).to have_content(snippet.title)
+ expect(page).not_to have_content('New snippet')
+ end
+ end
+end
diff --git a/spec/features/projects/user_create_dir_spec.rb b/spec/features/projects/user_create_dir_spec.rb
index 5dfdc465d7d..aeb7e0b7c33 100644
--- a/spec/features/projects/user_create_dir_spec.rb
+++ b/spec/features/projects/user_create_dir_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'New directory creation', feature: true, js: true do
- include TargetBranchHelpers
-
given(:user) { create(:user) }
given(:role) { :developer }
given(:project) { create(:project) }
@@ -36,23 +34,11 @@ feature 'New directory creation', feature: true, js: true do
end
end
- context 'with different target branch' do
- background do
- select_branch('feature')
- create_directory
- end
-
- scenario 'creates the directory in the different branch' do
- expect(page).to have_content 'feature'
- expect(page).to have_content 'The directory has been successfully created'
- end
- end
-
context 'with a new target branch' do
given(:new_branch_name) { 'new-feature' }
background do
- create_new_branch(new_branch_name)
+ fill_in :branch_name, with: new_branch_name
create_directory
end
diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb
index 49d7ef09e64..94f6bb16730 100644
--- a/spec/features/projects/wiki/markdown_preview_spec.rb
+++ b/spec/features/projects/wiki/markdown_preview_spec.rb
@@ -14,11 +14,12 @@ feature 'Projects > Wiki > User previews markdown changes', feature: true, js: t
background do
project.team << [user, :master]
+ WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
+
login_as(user)
visit namespace_project_path(project.namespace, project)
find('.shortcuts-wiki').trigger('click')
- WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
end
context "while creating a new wiki page" do
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index 667895bffa5..aa9164dd979 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -4,7 +4,9 @@ feature 'Protected Branches', feature: true, js: true do
let(:user) { create(:user, :admin) }
let(:project) { create(:project, :repository) }
- before { login_as(user) }
+ before do
+ login_as(user)
+ end
def set_protected_branch_name(branch_name)
find(".js-protected-branch-select").trigger('click')
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index 66236dbc7fc..63a20585776 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -4,7 +4,9 @@ feature 'Projected Tags', feature: true, js: true do
let(:user) { create(:user, :admin) }
let(:project) { create(:project, :repository) }
- before { login_as(user) }
+ before do
+ login_as(user)
+ end
def set_protected_tag_name(tag_name)
find(".js-protected-tag-select").click
diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb
new file mode 100644
index 00000000000..39b1c4acf52
--- /dev/null
+++ b/spec/features/reportable_note/commit_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe 'Reportable note on commit', :feature, :js do
+ include RepoHelpers
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ before do
+ project.add_master(user)
+ login_as 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)
+ end
+
+ it_behaves_like 'reportable note'
+ end
+
+ context 'a diff note' 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)
+ end
+
+ it_behaves_like 'reportable note'
+ end
+end
diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb
new file mode 100644
index 00000000000..5f526818994
--- /dev/null
+++ b/spec/features/reportable_note/issue_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe 'Reportable note on issue', :feature, :js do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let!(:note) { create(:note_on_issue, noteable: issue, project: project) }
+
+ before do
+ project.add_master(user)
+ login_as user
+
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it_behaves_like 'reportable note'
+end
diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb
new file mode 100644
index 00000000000..6d053d26626
--- /dev/null
+++ b/spec/features/reportable_note/merge_request_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe 'Reportable note on merge request', :feature, :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)
+ login_as user
+
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ context 'a normal note' do
+ let!(:note) { create(:note_on_merge_request, noteable: merge_request, project: project) }
+
+ it_behaves_like 'reportable note'
+ end
+
+ context 'a diff note' do
+ let!(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
+
+ it_behaves_like 'reportable note'
+ end
+end
diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb
new file mode 100644
index 00000000000..3f1e0cf9097
--- /dev/null
+++ b/spec/features/reportable_note/snippets_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe 'Reportable note on snippets', :feature, :js do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+
+ before do
+ project.add_master(user)
+ login_as user
+ end
+
+ describe 'on project snippet' do
+ let(:snippet) { create(:project_snippet, :public, project: project, author: user) }
+ let!(:note) { create(:note_on_project_snippet, noteable: snippet, project: project) }
+
+ before do
+ visit namespace_project_snippet_path(project.namespace, project, snippet)
+ end
+
+ it_behaves_like 'reportable note'
+ end
+
+ describe 'on personal snippet' do
+ let(:snippet) { create(:personal_snippet, :public, author: user) }
+ let!(:note) { create(:note_on_personal_snippet, noteable: snippet, author: user) }
+
+ before do
+ visit snippet_path(snippet)
+ end
+
+ it_behaves_like 'reportable note'
+ end
+end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 0e1cc9a0f73..e87d52f5c8f 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -4,7 +4,10 @@ describe "Runners" do
include GitlabRoutingHelper
let(:user) { create(:user) }
- before { login_as(user) }
+
+ before do
+ login_as(user)
+ end
describe "specific runners" do
before do
@@ -127,7 +130,9 @@ describe "Runners" do
end
context 'when runner has tags' do
- before { runner.update_attribute(:tag_list, ['tag']) }
+ before do
+ runner.update_attribute(:tag_list, ['tag'])
+ end
scenario 'user wants to prevent runner from running untagged job' do
visit runners_path(project)
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index 7834807b1f1..89d4f536b20 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -83,7 +83,9 @@ describe "Search", feature: true do
let(:project) { create(:project, :repository) }
let(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'Bug here') }
- before { note.update_attributes(commit_id: 12345678) }
+ before do
+ note.update_attributes(commit_id: 12345678)
+ end
it 'finds comment' do
visit namespace_project_path(project.namespace, project)
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 2a2655bbdb5..f33406a40a7 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -337,7 +337,9 @@ describe "Internal Project Access", feature: true do
subject { namespace_project_jobs_path(project.namespace, project) }
context "when allowed for public and internal" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -351,7 +353,9 @@ describe "Internal Project Access", feature: true do
end
context "when disallowed for public and internal" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -371,7 +375,9 @@ describe "Internal Project Access", feature: true do
subject { namespace_project_job_path(project.namespace, project, build.id) }
context "when allowed for public and internal" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -385,7 +391,9 @@ describe "Internal Project Access", feature: true do
end
context "when disallowed for public and internal" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
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 35d5163941e..16a1331b2f3 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -157,7 +157,9 @@ describe "Public Project Access", feature: true do
subject { namespace_project_jobs_path(project.namespace, project) }
context "when allowed for public" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -171,7 +173,9 @@ describe "Public Project Access", feature: true do
end
context "when disallowed for public" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -191,7 +195,9 @@ describe "Public Project Access", feature: true do
subject { namespace_project_job_path(project.namespace, project, build.id) }
context "when allowed for public" do
- before { project.update(public_builds: true) }
+ before do
+ project.update(public_builds: true)
+ end
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
@@ -205,7 +211,9 @@ describe "Public Project Access", feature: true do
end
context "when disallowed for public" do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
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 d7b6dda4946..5d6d1e79af2 100644
--- a/spec/features/signup_spec.rb
+++ b/spec/features/signup_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
feature 'Signup', feature: true do
describe 'signup with no errors' do
context "when sending confirmation email" do
- before { stub_application_setting(send_user_confirmation_email: true) }
+ before do
+ stub_application_setting(send_user_confirmation_email: true)
+ end
it 'creates the user account and sends a confirmation email' do
user = build(:user)
@@ -23,7 +25,9 @@ feature 'Signup', feature: true do
end
context "when not sending confirmation email" do
- before { stub_application_setting(send_user_confirmation_email: false) }
+ before do
+ stub_application_setting(send_user_confirmation_email: false)
+ end
it 'creates the user account and goes to dashboard' do
user = build(:user)
diff --git a/spec/features/snippets/create_snippet_spec.rb b/spec/features/snippets/create_snippet_spec.rb
index 31a2d4ae984..ddd31ede064 100644
--- a/spec/features/snippets/create_snippet_spec.rb
+++ b/spec/features/snippets/create_snippet_spec.rb
@@ -1,24 +1,93 @@
require 'rails_helper'
feature 'Create Snippet', :js, feature: true do
+ include DropzoneHelper
+
before do
login_as :user
visit new_snippet_path
end
- scenario 'Authenticated user creates a snippet' do
+ def fill_form
fill_in 'personal_snippet_title', with: 'My Snippet Title'
+ fill_in 'personal_snippet_description', with: 'My Snippet **Description**'
page.within('.file-editor') do
find('.ace_editor').native.send_keys 'Hello World!'
end
+ end
- click_button 'Create snippet'
+ scenario 'Authenticated user creates a snippet' do
+ fill_form
+
+ click_button('Create snippet')
wait_for_requests
expect(page).to have_content('My Snippet Title')
+ page.within('.snippet-header .description') do
+ expect(page).to have_content('My Snippet Description')
+ expect(page).to have_selector('strong')
+ end
expect(page).to have_content('Hello World!')
end
+ scenario 'previews a snippet with file' do
+ fill_in 'personal_snippet_description', with: 'My Snippet'
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ find('.js-md-preview-button').click
+
+ page.within('#new_personal_snippet .md-preview') 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})
+
+ visit(link)
+ expect(page.status_code).to eq(200)
+ end
+ end
+
+ scenario 'uploads a file when dragging into textarea' do
+ fill_form
+
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+
+ expect(page.find_field("personal_snippet_description").value).to have_content('banana_sample')
+
+ click_button('Create snippet')
+ 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})
+
+ visit(link)
+ expect(page.status_code).to eq(200)
+ end
+
+ scenario 'validation fails for the first time' do
+ fill_in 'personal_snippet_title', with: 'My Snippet Title'
+ click_button('Create snippet')
+
+ expect(page).to have_selector('#error_explanation')
+
+ fill_form
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+
+ click_button('Create snippet')
+ wait_for_requests
+
+ expect(page).to have_content('My Snippet Title')
+ page.within('.snippet-header .description') do
+ expect(page).to have_content('My Snippet Description')
+ expect(page).to have_selector('strong')
+ 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})
+
+ visit(link)
+ expect(page.status_code).to eq(200)
+ end
+
scenario 'Authenticated user creates a snippet with + in filename' do
fill_in 'personal_snippet_title', with: 'My Snippet Title'
page.within('.file-editor') do
diff --git a/spec/features/snippets/edit_snippet_spec.rb b/spec/features/snippets/edit_snippet_spec.rb
new file mode 100644
index 00000000000..89ae593db88
--- /dev/null
+++ b/spec/features/snippets/edit_snippet_spec.rb
@@ -0,0 +1,38 @@
+require 'rails_helper'
+
+feature 'Edit Snippet', :js, feature: true do
+ include DropzoneHelper
+
+ let(:file_name) { 'test.rb' }
+ let(:content) { 'puts "test"' }
+
+ let(:user) { create(:user) }
+ let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, author: user) }
+
+ before do
+ login_as(user)
+
+ visit edit_snippet_path(snippet)
+ wait_for_requests
+ end
+
+ it 'updates the snippet' do
+ fill_in 'personal_snippet_title', with: 'New Snippet Title'
+
+ click_button('Save changes')
+ wait_for_requests
+
+ expect(page).to have_content('New Snippet Title')
+ end
+
+ 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')
+
+ 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})
+ end
+end
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
index f7afc174019..44b0c89fac7 100644
--- a/spec/features/snippets/notes_on_personal_snippets_spec.rb
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe 'Comments on personal snippets', :js, feature: true do
+ include NoteInteractionHelpers
+
let!(:user) { create(:user) }
let!(:snippet) { create(:personal_snippet, :public) }
let!(:snippet_notes) do
@@ -22,6 +24,8 @@ describe 'Comments on personal snippets', :js, feature: true do
it 'contains notes for a snippet with correct action icons' do
expect(page).to have_selector('#notes-list li', count: 2)
+ open_more_actions_dropdown(snippet_notes[0])
+
# comment authored by current user
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
expect(page).to have_content(snippet_notes[0].note)
@@ -29,6 +33,8 @@ describe 'Comments on personal snippets', :js, feature: true do
expect(page).to have_selector('.note-emoji-button')
end
+ open_more_actions_dropdown(snippet_notes[1])
+
page.within("#notes-list li#note_#{snippet_notes[1].id}") do
expect(page).to have_content(snippet_notes[1].note)
expect(page).not_to have_selector('.js-note-delete')
@@ -68,6 +74,8 @@ describe 'Comments on personal snippets', :js, feature: true do
context 'when editing a note' do
it 'changes the text' do
+ open_more_actions_dropdown(snippet_notes[0])
+
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
click_on 'Edit comment'
end
@@ -89,8 +97,10 @@ describe 'Comments on personal snippets', :js, feature: true do
context 'when deleting a note' do
it 'removes the note from the snippet detail page' do
+ open_more_actions_dropdown(snippet_notes[0])
+
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
- click_on 'Remove comment'
+ click_on 'Delete comment'
end
wait_for_requests
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index 563e65d3cc5..51b1b8e2328 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -144,7 +144,9 @@ feature 'Task Lists', feature: true do
describe 'nested tasks', js: true do
let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) }
- before { visit_issue(project, issue) }
+ before do
+ visit_issue(project, issue)
+ end
it 'renders' do
expect(page).to have_selector('ul.task-list', count: 2)
diff --git a/spec/features/todos/todos_sorting_spec.rb b/spec/features/todos/todos_sorting_spec.rb
index 4d5bd476301..f012d250887 100644
--- a/spec/features/todos/todos_sorting_spec.rb
+++ b/spec/features/todos/todos_sorting_spec.rb
@@ -8,7 +8,9 @@ describe "Dashboard > User sorts todos", feature: true do
let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
let(:label_3) { create(:label, title: 'label_3', project: project, priority: 3) }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
context 'sort options' do
let(:issue_1) { create(:issue, title: 'issue_1', project: project) }
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index bb4b2aed0e3..feb2fe8a7d1 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -333,29 +333,6 @@ describe 'Dashboard Todos', feature: true do
end
end
- context 'User have large number of todos' do
- before do
- create_list(:todo, 101, :mentioned, user: user, project: project, target: issue, author: author)
-
- login_as(user)
- visit dashboard_todos_path
- end
-
- it 'shows 99+ for count >= 100 in notification' do
- expect(page).to have_selector('.todos-count', text: '99+')
- end
-
- it 'shows exact number in To do tab' do
- expect(page).to have_selector('.todos-pending .badge', text: '101')
- end
-
- it 'shows exact number for count < 100' do
- 3.times { first('.js-done-todo').click }
-
- expect(page).to have_selector('.todos-count', text: '98')
- end
- end
-
context 'User has a Build Failed todo' do
let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) }
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index c1ae6db00c6..2ea9992173d 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -5,7 +5,10 @@ feature 'Triggers', feature: true, js: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest_user) { create(:user) }
- before { login_as(user) }
+
+ before do
+ login_as(user)
+ end
before do
@project = create(:empty_project)
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
index 2fed8067042..dc21637967f 100644
--- a/spec/features/u2f_spec.rb
+++ b/spec/features/u2f_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
- before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) }
+ before do
+ allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true)
+ end
def manage_two_factor_authentication
click_on 'Manage two-factor authentication'
@@ -28,7 +30,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
end
describe 'when 2FA via OTP is disabled' do
- before { user.update_attribute(:otp_required_for_login, false) }
+ before do
+ user.update_attribute(:otp_required_for_login, false)
+ end
it 'does not allow registering a new device' do
visit profile_account_path
diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb
index 8509551ce4a..0a8db15c75f 100644
--- a/spec/features/unsubscribe_links_spec.rb
+++ b/spec/features/unsubscribe_links_spec.rb
@@ -56,7 +56,9 @@ describe 'Unsubscribe links', feature: true do
end
context 'when logged in' do
- before { login_as(recipient) }
+ before do
+ login_as(recipient)
+ end
it 'unsubscribes from the issue when visiting the link from the email body' do
visit body_link
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 f88a515f7fc..d9d6f2e2382 100644
--- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb
@@ -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/group/avatar/#{group.id}/dk.png"]))
+ expect(page).to have_selector(%Q(img[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 0dfd29045e5..eb8dbd76aab 100644
--- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
+++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb
@@ -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/user/avatar/#{user.id}/dk.png"]))
+ expect(page).to have_selector(%Q(img[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/user_can_display_performance_bar_spec.rb b/spec/features/user_can_display_performance_bar_spec.rb
new file mode 100644
index 00000000000..c2842255b86
--- /dev/null
+++ b/spec/features/user_can_display_performance_bar_spec.rb
@@ -0,0 +1,81 @@
+require 'rails_helper'
+
+describe 'User can display performacne 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')
+ end
+
+ context 'when user press `pb`' do
+ before 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')
+ end
+ end
+ end
+
+ shared_examples 'performance bar is enabled' do
+ it 'does not show the performance bar by default' do
+ expect(page).not_to have_css('#peek')
+ end
+
+ context 'when user press `pb`' do
+ before 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')
+ end
+ end
+ end
+
+ context 'when user is logged-out' do
+ before do
+ visit root_path
+ end
+
+ context 'when the gitlab_performance_bar feature is disabled' do
+ before do
+ Feature.disable('gitlab_performance_bar')
+ end
+
+ it_behaves_like 'performance bar is disabled'
+ end
+
+ context 'when the gitlab_performance_bar feature is enabled' do
+ before do
+ Feature.enable('gitlab_performance_bar')
+ end
+
+ it_behaves_like 'performance bar is disabled'
+ end
+ end
+
+ context 'when user is logged-in' do
+ before do
+ login_as :user
+
+ visit root_path
+ end
+
+ context 'when the gitlab_performance_bar feature is disabled' do
+ before do
+ Feature.disable('gitlab_performance_bar')
+ end
+
+ it_behaves_like 'performance bar is disabled'
+ end
+
+ context 'when the gitlab_performance_bar feature is enabled' do
+ before do
+ Feature.enable('gitlab_performance_bar')
+ end
+
+ it_behaves_like 'performance bar is enabled'
+ end
+ end
+end
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index fbe078bd136..c241dae12cf 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -45,7 +45,9 @@ feature 'Users', feature: true, js: true do
end
describe 'redirect alias routes' do
- before { user }
+ before do
+ expect(user).to be_persisted
+ end
scenario '/u/user1 redirects to user page' do
visit '/u/user1'
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 96151689359..8f2d60f2f1b 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -148,7 +148,9 @@ describe IssuesFinder do
let(:params) { { label_name: [label.title, label2.title].join(',') } }
let(:label2) { create(:label, project: project2) }
- before { create(:label_link, label: label2, target: issue2) }
+ before do
+ create(:label_link, label: label2, target: issue2)
+ end
it 'returns the unique issues with any of those labels' do
expect(issues).to contain_exactly(issue2)
diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb
index fd92664ca24..3f22b3a253d 100644
--- a/spec/finders/personal_access_tokens_finder_spec.rb
+++ b/spec/finders/personal_access_tokens_finder_spec.rb
@@ -25,49 +25,65 @@ describe PersonalAccessTokensFinder do
end
describe 'without impersonation' do
- before { params[:impersonation] = false }
+ before do
+ params[:impersonation] = false
+ end
it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) }
end
end
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) }
end
end
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it do
is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token,
@@ -81,7 +97,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
@@ -93,7 +111,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
@@ -109,7 +129,9 @@ describe PersonalAccessTokensFinder do
let!(:other_user_expired_impersonation_token) { create(:personal_access_token, :expired, :impersonation, user: user2) }
let!(:other_user_revoked_impersonation_token) { create(:personal_access_token, :revoked, :impersonation, user: user2) }
- before { params[:user] = user }
+ before do
+ params[:user] = user
+ end
it do
is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token,
@@ -118,49 +140,65 @@ describe PersonalAccessTokensFinder do
end
describe 'without impersonation' do
- before { params[:impersonation] = false }
+ before do
+ params[:impersonation] = false
+ end
it { is_expected.to contain_exactly(active_personal_access_token, revoked_personal_access_token, expired_personal_access_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_personal_access_token, expired_personal_access_token) }
end
end
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to contain_exactly(active_impersonation_token, revoked_impersonation_token, expired_impersonation_token) }
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it { is_expected.to contain_exactly(revoked_impersonation_token, expired_impersonation_token) }
end
end
describe 'with active state' do
- before { params[:state] = 'active' }
+ before do
+ params[:state] = 'active'
+ end
it { is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token) }
end
describe 'with inactive state' do
- before { params[:state] = 'inactive' }
+ before do
+ params[:state] = 'inactive'
+ end
it do
is_expected.to contain_exactly(expired_personal_access_token, revoked_personal_access_token,
@@ -174,7 +212,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
@@ -186,7 +226,9 @@ describe PersonalAccessTokensFinder do
it { is_expected.to eq(active_personal_access_token) }
describe 'with impersonation' do
- before { params[:impersonation] = true }
+ before do
+ params[:impersonation] = true
+ end
it { is_expected.to be_nil }
end
diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb
index e0e17af681a..304b0fb67fb 100644
--- a/spec/finders/personal_projects_finder_spec.rb
+++ b/spec/finders/personal_projects_finder_spec.rb
@@ -32,7 +32,9 @@ describe PersonalProjectsFinder do
end
context 'external' do
- before { current_user.update_attributes(external: true) }
+ before do
+ current_user.update_attributes(external: true)
+ end
it { is_expected.to eq([private_project, public_project]) }
end
diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb
index f2aeda241c1..2b19cda35b0 100644
--- a/spec/finders/pipelines_finder_spec.rb
+++ b/spec/finders/pipelines_finder_spec.rb
@@ -170,7 +170,7 @@ describe PipelinesFinder do
context 'when order_by and sort are specified' do
context 'when order_by user_id' do
let(:params) { { order_by: 'user_id', sort: 'asc' } }
- let!(:pipelines) { create_list(:ci_pipeline, 2, project: project, user: create(:user)) }
+ let!(:pipelines) { Array.new(2) { create(:ci_pipeline, project: project, user: create(:user)) } }
it 'sorts as user_id: :asc' do
is_expected.to match_array(pipelines)
diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb
index f7e7e733cf7..8be447418b0 100644
--- a/spec/finders/todos_finder_spec.rb
+++ b/spec/finders/todos_finder_spec.rb
@@ -6,7 +6,9 @@ describe TodosFinder do
let(:project) { create(:empty_project) }
let(:finder) { described_class }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
describe '#sort' do
context 'by date' do
diff --git a/spec/fixtures/api/schemas/list.json b/spec/fixtures/api/schemas/list.json
index 11a4caf6628..622a1e40d07 100644
--- a/spec/fixtures/api/schemas/list.json
+++ b/spec/fixtures/api/schemas/list.json
@@ -10,7 +10,7 @@
"id": { "type": "integer" },
"list_type": {
"type": "string",
- "enum": ["label", "closed"]
+ "enum": ["backlog", "label", "closed"]
},
"label": {
"type": ["object", "null"],
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 785fb724132..cc7f889b927 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
require 'spec_helper'
describe ApplicationHelper do
@@ -58,13 +59,13 @@ 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/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\" />"
allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)
- avatar_url = "#{gitlab_host}/uploads/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\" />"
@@ -84,12 +85,12 @@ describe ApplicationHelper do
it 'returns an url for the avatar' do
user = create(:user, avatar: File.open(uploaded_image_temp_path))
- avatar_url = "/uploads/user/avatar/#{user.id}/banana_sample.gif"
+ avatar_url = "/uploads/system/user/avatar/#{user.id}/banana_sample.gif"
expect(helper.avatar_icon(user.email).to_s).to match(avatar_url)
allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)
- avatar_url = "#{gitlab_host}/uploads/user/avatar/#{user.id}/banana_sample.gif"
+ avatar_url = "#{gitlab_host}/uploads/system/user/avatar/#{user.id}/banana_sample.gif"
expect(helper.avatar_icon(user.email).to_s).to match(avatar_url)
end
@@ -102,7 +103,7 @@ describe ApplicationHelper do
user = create(:user, avatar: File.open(uploaded_image_temp_path))
expect(helper.avatar_icon(user.email).to_s).
- to match("/gitlab/uploads/user/avatar/#{user.id}/banana_sample.gif")
+ to match("/gitlab/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
end
it 'calls gravatar_icon when no User exists with the given email' do
@@ -116,7 +117,7 @@ describe ApplicationHelper do
user = create(:user, avatar: File.open(uploaded_image_temp_path))
expect(helper.avatar_icon(user).to_s).
- to match("/uploads/user/avatar/#{user.id}/banana_sample.gif")
+ to match("/uploads/system/user/avatar/#{user.id}/banana_sample.gif")
end
end
end
@@ -256,4 +257,24 @@ describe ApplicationHelper do
it { expect(helper.active_when(true)).to eq('active') }
it { expect(helper.active_when(false)).to eq(nil) }
end
+
+ describe '#support_url' do
+ context 'when alternate support url is specified' do
+ let(:alternate_url) { 'http://company.example.com/getting-help' }
+
+ before do
+ allow(current_application_settings).to receive(:help_page_support_url) { alternate_url }
+ end
+
+ it 'returns the alternate support url' do
+ expect(helper.support_url).to eq(alternate_url)
+ end
+ end
+
+ context 'when alternate support url is not specified' do
+ it 'builds the support url from the promo_url' do
+ expect(helper.support_url).to eq(helper.promo_url + '/getting-help/')
+ end
+ end
+ end
end
diff --git a/spec/helpers/blame_helper_spec.rb b/spec/helpers/blame_helper_spec.rb
new file mode 100644
index 00000000000..b4368516d83
--- /dev/null
+++ b/spec/helpers/blame_helper_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+
+describe BlameHelper do
+ describe '#get_age_map_start_date' do
+ let(:dates) do
+ [Time.zone.local(2014, 3, 17, 0, 0, 0),
+ Time.zone.local(2011, 11, 2, 0, 0, 0),
+ Time.zone.local(2015, 7, 9, 0, 0, 0),
+ Time.zone.local(2013, 2, 24, 0, 0, 0),
+ Time.zone.local(2010, 9, 22, 0, 0, 0)]
+ end
+ let(:blame_groups) do
+ [
+ { commit: double(committed_date: dates[0]) },
+ { commit: double(committed_date: dates[1]) },
+ { commit: double(committed_date: dates[2]) }
+ ]
+ end
+
+ it 'returns the earliest date from a blame group' do
+ project = double(created_at: dates[3])
+
+ duration = helper.age_map_duration(blame_groups, project)
+
+ expect(duration[:started_days_ago]).to eq((duration[:now] - dates[1]).to_i / 1.day)
+ end
+
+ it 'returns the earliest date from a project' do
+ project = double(created_at: dates[4])
+
+ duration = helper.age_map_duration(blame_groups, project)
+
+ expect(duration[:started_days_ago]).to eq((duration[:now] - dates[4]).to_i / 1.day)
+ end
+ end
+
+ describe '#age_map_class' do
+ let(:dates) do
+ [Time.zone.local(2014, 3, 17, 0, 0, 0)]
+ end
+ let(:blame_groups) do
+ [
+ { commit: double(committed_date: dates[0]) }
+ ]
+ end
+ let(:duration) do
+ project = double(created_at: dates[0])
+ helper.age_map_duration(blame_groups, project)
+ end
+
+ it 'returns blame-commit-age-9 when oldest' do
+ expect(helper.age_map_class(dates[0], duration)).to eq 'blame-commit-age-9'
+ end
+
+ it 'returns blame-commit-age-0 class when newest' do
+ expect(helper.age_map_class(duration[:now], duration)).to eq 'blame-commit-age-0'
+ end
+ end
+end
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index a74615e07f9..0ac030d3171 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -8,7 +8,7 @@ describe DiffHelper do
let(:commit) { project.commit(sample_commit.id) }
let(:diffs) { commit.raw_diffs }
let(:diff) { diffs.first }
- let(:diff_refs) { [commit.parent, commit] }
+ let(:diff_refs) { commit.diff_refs }
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) }
describe 'diff_view' do
@@ -207,4 +207,41 @@ describe DiffHelper do
expect(output).not_to have_css 'td:nth-child(3)'
end
end
+
+ context 'viewer related' do
+ let(:viewer) { diff_file.simple_viewer }
+
+ before do
+ assign(:project, project)
+ end
+
+ describe '#diff_render_error_reason' do
+ context 'for error :too_large' do
+ before do
+ expect(viewer).to receive(:render_error).and_return(:too_large)
+ end
+
+ it 'returns an error message' do
+ expect(helper.diff_render_error_reason(viewer)).to eq('it is too large')
+ end
+ end
+
+ context 'for error :server_side_but_stored_externally' do
+ before do
+ expect(viewer).to receive(:render_error).and_return(:server_side_but_stored_externally)
+ expect(diff_file).to receive(:external_storage).and_return(:lfs)
+ end
+
+ it 'returns an error message' do
+ expect(helper.diff_render_error_reason(viewer)).to eq('it is stored in LFS')
+ end
+ end
+ end
+
+ describe '#diff_render_error_options' do
+ it 'includes a "view the blob" link' do
+ expect(helper.diff_render_error_options(viewer)).to include(/view the blob/)
+ end
+ end
+ end
end
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index cd112dbb2fb..c68e4f56b05 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/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/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index c8b0d86425f..0337afa4452 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -9,7 +9,7 @@ describe GroupsHelper do
group.avatar = fixture_file_upload(avatar_file_path)
group.save!
expect(group_icon(group.path).to_s).
- to match("/uploads/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
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 355a4845afb..cc861af8533 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -256,4 +256,14 @@ describe NotesHelper do
expect(helper.form_resources).to eq([@project.namespace, @project, @note])
end
end
+
+ describe '#noteable_note_url' do
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:note) { create(:note_on_issue, noteable: issue, project: project) }
+
+ it 'returns the noteable url with an anchor to the note' do
+ expect(noteable_note_url(note)).to match("/#{project.namespace.path}/#{project.path}/issues/#{issue.iid}##{dom_id(note)}")
+ end
+ end
end
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index 9d5f009ebe1..9ecaabc04ed 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -12,5 +12,11 @@ describe NotificationsHelper do
describe 'notification_title' do
it { expect(notification_title(:watch)).to match('Watch') }
it { expect(notification_title(:mention)).to match('On mention') }
+ it { expect(notification_title(:global)).to match('Global') }
+ end
+
+ describe '#notification_event_name' do
+ it { expect(notification_event_name(:success_pipeline)).to match('Successful pipeline') }
+ it { expect(notification_event_name(:failed_pipeline)).to match('Failed pipeline') }
end
end
diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb
index 2cc0b40b2d0..dff2784f21f 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/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/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb
new file mode 100644
index 00000000000..b33b3f3a228
--- /dev/null
+++ b/spec/helpers/profiles_helper_spec.rb
@@ -0,0 +1,36 @@
+require 'rails_helper'
+
+describe ProfilesHelper do
+ describe '#email_provider_label' do
+ it "returns nil for users without external email" do
+ user = create(:user)
+ allow(helper).to receive(:current_user).and_return(user)
+
+ expect(helper.email_provider_label).to be_nil
+ end
+
+ it "returns omniauth provider label for users with external email" do
+ stub_cas_omniauth_provider
+ cas_user = create(:omniauth_user, provider: 'cas3', external_email: true, email_provider: 'cas3')
+ allow(helper).to receive(:current_user).and_return(cas_user)
+
+ expect(helper.email_provider_label).to eq('CAS')
+ end
+
+ it "returns 'LDAP' for users with external email but no email provider" do
+ ldap_user = create(:omniauth_user, external_email: true)
+ allow(helper).to receive(:current_user).and_return(ldap_user)
+
+ expect(helper.email_provider_label).to eq('LDAP')
+ end
+ end
+
+ def stub_cas_omniauth_provider
+ provider = OpenStruct.new(
+ 'name' => 'cas3',
+ 'label' => 'CAS'
+ )
+
+ stub_omniauth_setting(providers: [provider])
+ end
+end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index a695621b87a..9a4086725d2 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -250,7 +250,9 @@ describe ProjectsHelper do
end
context "when project is private" do
- before { project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
+ before do
+ project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
it "shows only allowed options" do
helper.instance_variable_set(:@project, project)
@@ -300,4 +302,37 @@ describe ProjectsHelper do
expect(helper.send(:visibility_select_options, project, Gitlab::VisibilityLevel::PRIVATE)).to include('Private')
end
end
+
+ describe '#get_project_nav_tabs' do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ allow(helper).to receive(:can?) { true }
+ end
+
+ subject do
+ helper.send(:get_project_nav_tabs, project, user)
+ end
+
+ context 'when builds feature is enabled' do
+ before do
+ allow(project).to receive(:builds_enabled?).and_return(true)
+ end
+
+ it "does include pipelines tab" do
+ is_expected.to include(:pipelines)
+ end
+ end
+
+ context 'when builds feature is disabled' do
+ before do
+ allow(project).to receive(:builds_enabled?).and_return(false)
+ end
+
+ it "do not include pipelines tab" do
+ is_expected.not_to include(:pipelines)
+ end
+ end
+ end
end
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index 50060a0925d..18a41ca24e3 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -1,6 +1,19 @@
require "spec_helper"
describe TodosHelper do
+ describe '#todos_count_format' do
+ it 'shows fuzzy count for 100 or more items' do
+ expect(helper.todos_count_format(100)).to eq '99+'
+ expect(helper.todos_count_format(1000)).to eq '99+'
+ end
+
+ it 'shows exact count for 99 or fewer items' do
+ expect(helper.todos_count_format(99)).to eq '99'
+ expect(helper.todos_count_format(50)).to eq '50'
+ expect(helper.todos_count_format(1)).to eq '1'
+ end
+ end
+
describe '#todo_projects_options' do
let(:projects) { create_list(:empty_project, 3) }
let(:user) { create(:user) }
diff --git a/spec/helpers/u2f_helper_spec.rb b/spec/helpers/u2f_helper_spec.rb
new file mode 100644
index 00000000000..0d65b4fe0b8
--- /dev/null
+++ b/spec/helpers/u2f_helper_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe U2fHelper do
+ describe 'when not on mobile' do
+ it 'does not inject u2f on chrome 40' do
+ device = double(mobile?: false)
+ browser = double(chrome?: true, opera?: false, version: 40, device: device)
+ allow(helper).to receive(:browser).and_return(browser)
+ expect(helper.inject_u2f_api?).to eq false
+ end
+
+ it 'injects u2f on chrome 41' do
+ device = double(mobile?: false)
+ browser = double(chrome?: true, opera?: false, version: 41, device: device)
+ allow(helper).to receive(:browser).and_return(browser)
+ expect(helper.inject_u2f_api?).to eq true
+ end
+
+ it 'does not inject u2f on opera 39' do
+ device = double(mobile?: false)
+ browser = double(chrome?: false, opera?: true, version: 39, device: device)
+ allow(helper).to receive(:browser).and_return(browser)
+ expect(helper.inject_u2f_api?).to eq false
+ end
+
+ it 'injects u2f on opera 40' do
+ device = double(mobile?: false)
+ browser = double(chrome?: false, opera?: true, version: 40, device: device)
+ allow(helper).to receive(:browser).and_return(browser)
+ expect(helper.inject_u2f_api?).to eq true
+ end
+ end
+
+ describe 'when on mobile' do
+ it 'does not inject u2f on chrome 41' do
+ device = double(mobile?: true)
+ browser = double(chrome?: true, opera?: false, version: 41, device: device)
+ allow(helper).to receive(:browser).and_return(browser)
+ expect(helper.inject_u2f_api?).to eq false
+ end
+
+ it 'does not inject u2f on opera 40' do
+ device = double(mobile?: true)
+ browser = double(chrome?: false, opera?: true, version: 40, device: device)
+ allow(helper).to receive(:browser).and_return(browser)
+ expect(helper.inject_u2f_api?).to eq false
+ end
+ end
+end
diff --git a/spec/initializers/8_metrics_spec.rb b/spec/initializers/8_metrics_spec.rb
index 570754621f3..a507d7f7f2b 100644
--- a/spec/initializers/8_metrics_spec.rb
+++ b/spec/initializers/8_metrics_spec.rb
@@ -7,6 +7,7 @@ describe 'instrument_classes', lib: true do
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)
end
diff --git a/spec/javascripts/blob/create_branch_dropdown_spec.js b/spec/javascripts/blob/create_branch_dropdown_spec.js
deleted file mode 100644
index 6dbaa47c544..00000000000
--- a/spec/javascripts/blob/create_branch_dropdown_spec.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import '~/gl_dropdown';
-import '~/blob/create_branch_dropdown';
-import '~/blob/target_branch_dropdown';
-
-describe('CreateBranchDropdown', () => {
- const fixtureTemplate = 'static/target_branch_dropdown.html.raw';
- // selectors
- const createBranchSel = '.js-new-branch-btn';
- const backBtnSel = '.dropdown-menu-back';
- const cancelBtnSel = '.js-cancel-branch-btn';
- const branchNameSel = '#new_branch_name';
- const branchName = 'new_name';
- let dropdown;
-
- function createDropdown() {
- const dropdownEl = document.querySelector('.js-project-branches-dropdown');
- const projectBranches = getJSONFixture('project_branches.json');
- dropdown = new gl.TargetBranchDropDown(dropdownEl);
- dropdown.cachedRefs = projectBranches;
- return dropdown;
- }
-
- function createBranchBtn() {
- return document.querySelector(createBranchSel);
- }
-
- function backBtn() {
- return document.querySelector(backBtnSel);
- }
-
- function cancelBtn() {
- return document.querySelector(cancelBtnSel);
- }
-
- function branchNameEl() {
- return document.querySelector(branchNameSel);
- }
-
- function changeBranchName(text) {
- branchNameEl().value = text;
- branchNameEl().dispatchEvent(new Event('change'));
- }
-
- preloadFixtures(fixtureTemplate);
-
- beforeEach(() => {
- loadFixtures(fixtureTemplate);
- createDropdown();
- });
-
- it('disable submit when branch name is empty', () => {
- expect(createBranchBtn()).toBeDisabled();
- });
-
- it('enable submit when branch name is present', () => {
- changeBranchName(branchName);
-
- expect(createBranchBtn()).not.toBeDisabled();
- });
-
- it('resets the form when cancel btn is clicked and triggers dropdownback', () => {
- const spyBackEvent = spyOnEvent(backBtnSel, 'click');
- changeBranchName(branchName);
-
- cancelBtn().click();
-
- expect(branchNameEl()).toHaveValue('');
- expect(spyBackEvent).toHaveBeenTriggered();
- });
-
- it('resets the form when back btn is clicked', () => {
- changeBranchName(branchName);
-
- backBtn().click();
-
- expect(branchNameEl()).toHaveValue('');
- });
-
- describe('new branch creation', () => {
- beforeEach(() => {
- changeBranchName(branchName);
- });
- it('sets the new branch name and updates the dropdown', () => {
- spyOn(dropdown, 'setNewBranch');
-
- createBranchBtn().click();
-
- expect(dropdown.setNewBranch).toHaveBeenCalledWith(branchName);
- });
-
- it('resets the form', () => {
- createBranchBtn().click();
-
- expect(branchNameEl()).toHaveValue('');
- });
-
- it('is triggered with enter keypress', () => {
- spyOn(dropdown, 'setNewBranch');
- const enterEvent = new Event('keydown');
- enterEvent.which = 13;
- branchNameEl().dispatchEvent(enterEvent);
-
- expect(dropdown.setNewBranch).toHaveBeenCalledWith(branchName);
- });
- });
-});
diff --git a/spec/javascripts/blob/target_branch_dropdown_spec.js b/spec/javascripts/blob/target_branch_dropdown_spec.js
deleted file mode 100644
index 99c9537d2ec..00000000000
--- a/spec/javascripts/blob/target_branch_dropdown_spec.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import '~/gl_dropdown';
-import '~/blob/create_branch_dropdown';
-import '~/blob/target_branch_dropdown';
-
-describe('TargetBranchDropdown', () => {
- const fixtureTemplate = 'static/target_branch_dropdown.html.raw';
- let dropdown;
-
- function createDropdown() {
- const projectBranches = getJSONFixture('project_branches.json');
- const dropdownEl = document.querySelector('.js-project-branches-dropdown');
- dropdown = new gl.TargetBranchDropDown(dropdownEl);
- dropdown.cachedRefs = projectBranches;
- dropdown.refreshData();
- return dropdown;
- }
-
- function submitBtn() {
- return document.querySelector('button[type="submit"]');
- }
-
- function searchField() {
- return document.querySelector('.dropdown-page-one .dropdown-input-field');
- }
-
- function element() {
- return document.querySelectorAll('div.dropdown-content li a');
- }
-
- function elementAtIndex(index) {
- return element()[index];
- }
-
- function clickElementAtIndex(index) {
- elementAtIndex(index).click();
- }
-
- preloadFixtures(fixtureTemplate);
-
- beforeEach(() => {
- loadFixtures(fixtureTemplate);
- createDropdown();
- });
-
- it('disable submit when branch is not selected', () => {
- document.querySelector('input[name="target_branch"]').value = null;
- clickElementAtIndex(1);
-
- expect(submitBtn().getAttribute('disabled')).toEqual('');
- });
-
- it('enable submit when a branch is selected', () => {
- clickElementAtIndex(1);
-
- expect(submitBtn().getAttribute('disabled')).toBe(null);
- });
-
- it('triggers change.branch event on a branch click', () => {
- spyOnEvent(dropdown.$dropdown, 'change.branch');
- clickElementAtIndex(0);
-
- expect('change.branch').toHaveBeenTriggeredOn(dropdown.$dropdown);
- });
-
- describe('dropdownData', () => {
- it('cache the refs', () => {
- const refs = dropdown.cachedRefs;
- dropdown.cachedRefs = null;
-
- dropdown.dropdownData(refs);
-
- expect(dropdown.cachedRefs).toEqual(refs);
- });
-
- it('returns the Branches with the newBranch and defaultBranch', () => {
- const refs = dropdown.cachedRefs;
- dropdown.branchInput.value = 'master';
- dropdown.newBranch = { id: 'new_branch', text: 'new_branch', title: 'new_branch' };
-
- const branches = dropdown.dropdownData(refs).Branches;
-
- expect(branches.length).toEqual(4);
- expect(branches[0]).toEqual(dropdown.newBranch);
- expect(branches[1]).toEqual({ id: 'master', text: 'master', title: 'master' });
- expect(branches[2]).toEqual({ id: 'development', text: 'development', title: 'development' });
- expect(branches[3]).toEqual({ id: 'staging', text: 'staging', title: 'staging' });
- });
- });
-
- describe('setNewBranch', () => {
- it('adds the new branch and select it', () => {
- const branchName = 'new_branch';
-
- dropdown.setNewBranch(branchName);
-
- expect(elementAtIndex(0)).toHaveClass('is-active');
- expect(elementAtIndex(0)).toContainHtml(branchName);
- });
-
- it("doesn't add a new branch if already exists in the list", () => {
- const branchName = elementAtIndex(0).text;
- const initialLength = element().length;
-
- dropdown.setNewBranch(branchName);
-
- expect(element().length).toEqual(initialLength);
- });
-
- it('clears the search filter', () => {
- const branchName = elementAtIndex(0).text;
- searchField().value = 'searching';
-
- dropdown.setNewBranch(branchName);
-
- expect(searchField().value).toEqual('');
- });
- });
-});
diff --git a/spec/javascripts/boards/components/board_spec.js b/spec/javascripts/boards/components/board_spec.js
new file mode 100644
index 00000000000..c4e8966ad6c
--- /dev/null
+++ b/spec/javascripts/boards/components/board_spec.js
@@ -0,0 +1,112 @@
+import Vue from 'vue';
+import '~/boards/services/board_service';
+import '~/boards/components/board';
+import '~/boards/models/list';
+
+describe('Board component', () => {
+ let vm;
+ let el;
+
+ beforeEach((done) => {
+ loadFixtures('boards/show.html.raw');
+
+ el = document.createElement('div');
+ document.body.appendChild(el);
+
+ // eslint-disable-next-line no-undef
+ gl.boardService = new BoardService('/', '/', 1);
+
+ vm = new gl.issueBoards.Board({
+ propsData: {
+ boardId: '1',
+ disabled: false,
+ issueLinkBase: '/',
+ rootPath: '/',
+ // eslint-disable-next-line no-undef
+ list: new List({
+ id: 1,
+ position: 0,
+ title: 'test',
+ list_type: 'backlog',
+ }),
+ },
+ }).$mount(el);
+
+ Vue.nextTick(done);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ // remove the component from the DOM
+ document.querySelector('.board').remove();
+
+ localStorage.removeItem(`boards.${vm.boardId}.${vm.list.type}.expanded`);
+ });
+
+ it('board is expandable when list type is backlog', () => {
+ expect(
+ vm.$el.classList.contains('is-expandable'),
+ ).toBe(true);
+ });
+
+ it('board is expandable when list type is closed', (done) => {
+ vm.list.type = 'closed';
+
+ Vue.nextTick(() => {
+ expect(
+ vm.$el.classList.contains('is-expandable'),
+ ).toBe(true);
+
+ done();
+ });
+ });
+
+ it('board is not expandable when list type is label', (done) => {
+ vm.list.type = 'label';
+ vm.list.isExpandable = false;
+
+ Vue.nextTick(() => {
+ expect(
+ vm.$el.classList.contains('is-expandable'),
+ ).toBe(false);
+
+ done();
+ });
+ });
+
+ it('collapses when clicking header', (done) => {
+ vm.$el.querySelector('.board-header').click();
+
+ Vue.nextTick(() => {
+ expect(
+ vm.$el.classList.contains('is-collapsed'),
+ ).toBe(true);
+
+ done();
+ });
+ });
+
+ it('created sets isExpanded to true from localStorage', (done) => {
+ vm.$el.querySelector('.board-header').click();
+
+ return Vue.nextTick()
+ .then(() => {
+ expect(
+ vm.$el.classList.contains('is-collapsed'),
+ ).toBe(true);
+
+ // call created manually
+ vm.$options.created[0].call(vm);
+
+ return Vue.nextTick();
+ })
+ .then(() => {
+ expect(
+ vm.$el.classList.contains('is-collapsed'),
+ ).toBe(true);
+
+ done();
+ });
+ });
+});
diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js b/spec/javascripts/bootstrap_linked_tabs_spec.js
index a27dc48b3fd..93dc60d59fe 100644
--- a/spec/javascripts/bootstrap_linked_tabs_spec.js
+++ b/spec/javascripts/bootstrap_linked_tabs_spec.js
@@ -1,15 +1,6 @@
import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
(() => {
- // TODO: remove this hack!
- // PhantomJS causes spyOn to panic because replaceState isn't "writable"
- let phantomjs;
- try {
- phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
- } catch (err) {
- phantomjs = false;
- }
-
describe('Linked Tabs', () => {
preloadFixtures('static/linked_tabs.html.raw');
@@ -19,9 +10,7 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
describe('when is initialized', () => {
beforeEach(() => {
- if (!phantomjs) {
- spyOn(window.history, 'replaceState').and.callFake(function () {});
- }
+ spyOn(window.history, 'replaceState').and.callFake(function () {});
});
it('should activate the tab correspondent to the given action', () => {
@@ -47,7 +36,7 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
describe('on click', () => {
it('should change the url according to the clicked tab', () => {
- const historySpy = !phantomjs && spyOn(history, 'replaceState').and.callFake(() => {});
+ const historySpy = spyOn(history, 'replaceState').and.callFake(() => {});
const linkedTabs = new LinkedTabs({
action: 'show',
diff --git a/spec/javascripts/build_spec.js b/spec/javascripts/build_spec.js
index 461908f3fde..be90dbdd88a 100644
--- a/spec/javascripts/build_spec.js
+++ b/spec/javascripts/build_spec.js
@@ -58,7 +58,7 @@ describe('Build', () => {
it('displays the remove date correctly', () => {
const removeDateElement = document.querySelector('.js-artifacts-remove');
- expect(removeDateElement.innerText.trim()).toBe('1 year');
+ expect(removeDateElement.innerText.trim()).toBe('1 year remaining');
});
});
@@ -132,23 +132,6 @@ describe('Build', () => {
expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/);
expect($('#build-trace .js-build-output').text()).toMatch(/Different/);
});
-
- it('reloads the page when the build is done', () => {
- spyOn(gl.utils, 'visitUrl');
- const deferred = $.Deferred();
-
- spyOn($, 'ajax').and.returnValue(deferred.promise());
- deferred.resolve({
- html: '<span>Final</span>',
- status: 'passed',
- append: true,
- complete: true,
- });
-
- this.build = new Build();
-
- expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL);
- });
});
describe('truncated information', () => {
diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js
index 44a4386b250..ace95000468 100644
--- a/spec/javascripts/commits_spec.js
+++ b/spec/javascripts/commits_spec.js
@@ -5,15 +5,6 @@ import '~/pager';
import '~/commits';
(() => {
- // TODO: remove this hack!
- // PhantomJS causes spyOn to panic because replaceState isn't "writable"
- let phantomjs;
- try {
- phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
- } catch (err) {
- phantomjs = false;
- }
-
describe('Commits List', () => {
beforeEach(() => {
setFixtures(`
@@ -61,9 +52,7 @@ import '~/commits';
CommitsList.init(25);
CommitsList.searchField.val('');
- if (!phantomjs) {
- spyOn(history, 'replaceState').and.stub();
- }
+ spyOn(history, 'replaceState').and.stub();
ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => {
req.success({
data: '<li>Result</li>',
diff --git a/spec/javascripts/datetime_utility_spec.js b/spec/javascripts/datetime_utility_spec.js
index e347c980c78..e54ea11b08c 100644
--- a/spec/javascripts/datetime_utility_spec.js
+++ b/spec/javascripts/datetime_utility_spec.js
@@ -1,7 +1,27 @@
-import '~/lib/utils/datetime_utility';
+import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
(() => {
describe('Date time utils', () => {
+ describe('timeFor', () => {
+ it('returns `past due` when in past', () => {
+ const date = new Date();
+ date.setFullYear(date.getFullYear() - 1);
+
+ expect(
+ gl.utils.timeFor(date),
+ ).toBe('Past due');
+ });
+
+ it('returns remaining time when in the future', () => {
+ const date = new Date();
+ date.setFullYear(date.getFullYear() + 1);
+
+ expect(
+ gl.utils.timeFor(date),
+ ).toBe('1 year remaining');
+ });
+ });
+
describe('get day name', () => {
it('should return Sunday', () => {
const day = gl.utils.getDayName(new Date('07/17/2016'));
@@ -62,4 +82,13 @@ import '~/lib/utils/datetime_utility';
});
});
});
+
+ describe('timeIntervalInWords', () => {
+ it('should return string with number of minutes and seconds', () => {
+ expect(timeIntervalInWords(9.54)).toEqual('9 seconds');
+ expect(timeIntervalInWords(1)).toEqual('1 second');
+ expect(timeIntervalInWords(200)).toEqual('3 minutes 20 seconds');
+ expect(timeIntervalInWords(6008)).toEqual('100 minutes 8 seconds');
+ });
+ });
})();
diff --git a/spec/javascripts/deploy_keys/components/key_spec.js b/spec/javascripts/deploy_keys/components/key_spec.js
index 793ab8c451d..a4b98f6140d 100644
--- a/spec/javascripts/deploy_keys/components/key_spec.js
+++ b/spec/javascripts/deploy_keys/components/key_spec.js
@@ -39,9 +39,15 @@ describe('Deploy keys key', () => {
).toBe(`created ${gl.utils.getTimeago().format(deployKey.created_at)}`);
});
+ it('shows edit button', () => {
+ expect(
+ vm.$el.querySelectorAll('.btn')[0].textContent.trim(),
+ ).toBe('Edit');
+ });
+
it('shows remove button', () => {
expect(
- vm.$el.querySelector('.btn').textContent.trim(),
+ vm.$el.querySelectorAll('.btn')[1].textContent.trim(),
).toBe('Remove');
});
@@ -71,9 +77,15 @@ describe('Deploy keys key', () => {
setTimeout(done);
});
+ it('shows edit button', () => {
+ expect(
+ vm.$el.querySelectorAll('.btn')[0].textContent.trim(),
+ ).toBe('Edit');
+ });
+
it('shows enable button', () => {
expect(
- vm.$el.querySelector('.btn').textContent.trim(),
+ vm.$el.querySelectorAll('.btn')[1].textContent.trim(),
).toBe('Enable');
});
@@ -82,7 +94,7 @@ describe('Deploy keys key', () => {
Vue.nextTick(() => {
expect(
- vm.$el.querySelector('.btn').textContent.trim(),
+ vm.$el.querySelectorAll('.btn')[1].textContent.trim(),
).toBe('Disable');
done();
diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
index 9c8629ef9f0..6d00d71f145 100644
--- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js
@@ -97,6 +97,49 @@ describe('Filtered Search Manager', () => {
});
});
+ describe('searchState', () => {
+ beforeEach(() => {
+ spyOn(gl.FilteredSearchManager.prototype, 'search').and.callFake(() => {});
+ });
+
+ it('should blur button', () => {
+ const e = {
+ currentTarget: {
+ blur: () => {},
+ },
+ };
+ spyOn(e.currentTarget, 'blur').and.callThrough();
+ manager.searchState(e);
+
+ expect(e.currentTarget.blur).toHaveBeenCalled();
+ });
+
+ it('should not call search if there is no state', () => {
+ const e = {
+ currentTarget: {
+ blur: () => {},
+ },
+ };
+
+ manager.searchState(e);
+ expect(gl.FilteredSearchManager.prototype.search).not.toHaveBeenCalled();
+ });
+
+ it('should call search when there is state', () => {
+ const e = {
+ currentTarget: {
+ blur: () => {},
+ dataset: {
+ state: 'opened',
+ },
+ },
+ };
+
+ manager.searchState(e);
+ expect(gl.FilteredSearchManager.prototype.search).toHaveBeenCalledWith('opened');
+ });
+ });
+
describe('search', () => {
const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened';
diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb
new file mode 100644
index 00000000000..d7c3dc0a235
--- /dev/null
+++ b/spec/javascripts/fixtures/boards.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:admin) { create(:admin) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project, :repository, namespace: namespace, path: 'boards-project') }
+
+ render_views
+
+ before(:all) do
+ clean_frontend_fixtures('boards/')
+ end
+
+ before(:each) do
+ sign_in(admin)
+ end
+
+ it 'boards/show.html.raw' do |example|
+ get(:index,
+ namespace_id: project.namespace,
+ project_id: project)
+
+ expect(response).to be_success
+ store_frontend_fixture(response, example.description)
+ end
+end
diff --git a/spec/javascripts/fixtures/project_branches.json b/spec/javascripts/fixtures/project_branches.json
deleted file mode 100644
index a96a4c0c095..00000000000
--- a/spec/javascripts/fixtures/project_branches.json
+++ /dev/null
@@ -1,5 +0,0 @@
-[
- "master",
- "development",
- "staging"
-]
diff --git a/spec/javascripts/fixtures/target_branch_dropdown.html.haml b/spec/javascripts/fixtures/target_branch_dropdown.html.haml
deleted file mode 100644
index 821fb7940a0..00000000000
--- a/spec/javascripts/fixtures/target_branch_dropdown.html.haml
+++ /dev/null
@@ -1,28 +0,0 @@
-%form.js-edit-blob-form
- %input{type: 'hidden', name: 'target_branch', value: 'master'}
- %div
- .dropdown
- %button.dropdown-menu-toggle.js-project-branches-dropdown.js-target-branch{type: 'button', data: {toggle: 'dropdown', selected: 'master', field_name: 'target_branch', form_id: '.js-edit-blob-form'}}
- .dropdown-menu.dropdown-menu-selectable.dropdown-menu-paging
- .dropdown-page-one
- .dropdown-title 'Select branch'
- .dropdown-input
- %input.dropdown-input-field{type: 'search', value: ''}
- %i.fa.fa-search.dropdown-input-search
- %i.fa.fa-times-dropdown-input-clear.js-dropdown-input-clear{role: 'button'}
- .dropdown-content
- .dropdown-footer
- %ul.dropdown-footer-list
- %li
- %a.create-new-branch.dropdown-toggle-page{href: "#"}
- Create new branch
- .dropdown-page-two.dropdown-new-branch
- %button.dropdown-title-button.dropdown-menu-back{type: 'button'}
- .dropdown_title 'Create new branch'
- .dropdown_content
- %input#new_branch_name.default-dropdown-input{ type: "text", placeholder: "Name new branch" }
- %button.btn.btn-primary.pull-left.js-new-branch-btn{ type: "button" }
- Create
- %button.btn.btn-default.pull-right.js-cancel-branch-btn{ type: "button" }
- Cancel
- %button{type: 'submit'}
diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js
index 3292590b9ed..10fcc590c89 100644
--- a/spec/javascripts/gl_dropdown_spec.js
+++ b/spec/javascripts/gl_dropdown_spec.js
@@ -185,7 +185,7 @@ import '~/lib/utils/url_utility';
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
- it('should focus on input when opening for the second time', () => {
+ it('should focus on input when opening for the second time after transition', () => {
remoteCallback();
this.dropdownContainerElement.trigger({
type: 'keyup',
@@ -193,6 +193,7 @@ import '~/lib/utils/url_utility';
keyCode: ARROW_KEYS.ESC
});
this.dropdownButtonElement.click();
+ this.dropdownContainerElement.trigger('transitionend');
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
});
@@ -201,6 +202,7 @@ import '~/lib/utils/url_utility';
it('should focus input when passing array data to drop down', () => {
initDropDown.call(this, false, true);
this.dropdownButtonElement.click();
+ this.dropdownContainerElement.trigger('transitionend');
expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
});
});
diff --git a/spec/javascripts/gl_emoji_spec.js b/spec/javascripts/gl_emoji_spec.js
index b2b46640e5b..a09e0072fa8 100644
--- a/spec/javascripts/gl_emoji_spec.js
+++ b/spec/javascripts/gl_emoji_spec.js
@@ -192,6 +192,9 @@ describe('gl_emoji', () => {
});
describe('isFlagEmoji', () => {
+ it('should gracefully handle empty string', () => {
+ expect(isFlagEmoji('')).toBeFalsy();
+ });
it('should detect flag_ac', () => {
expect(isFlagEmoji('🇦🇨')).toBeTruthy();
});
@@ -216,6 +219,9 @@ describe('gl_emoji', () => {
});
describe('isKeycapEmoji', () => {
+ it('should gracefully handle empty string', () => {
+ expect(isKeycapEmoji('')).toBeFalsy();
+ });
it('should detect one(keycap)', () => {
expect(isKeycapEmoji('1️⃣')).toBeTruthy();
});
@@ -231,6 +237,9 @@ describe('gl_emoji', () => {
});
describe('isSkinToneComboEmoji', () => {
+ it('should gracefully handle empty string', () => {
+ expect(isSkinToneComboEmoji('')).toBeFalsy();
+ });
it('should detect hand_splayed_tone5', () => {
expect(isSkinToneComboEmoji('🖐🏿')).toBeTruthy();
});
@@ -255,6 +264,9 @@ describe('gl_emoji', () => {
});
describe('isHorceRacingSkinToneComboEmoji', () => {
+ it('should gracefully handle empty string', () => {
+ expect(isHorceRacingSkinToneComboEmoji('')).toBeFalsy();
+ });
it('should detect horse_racing_tone2', () => {
expect(isHorceRacingSkinToneComboEmoji('🏇🏼')).toBeTruthy();
});
@@ -264,6 +276,9 @@ describe('gl_emoji', () => {
});
describe('isPersonZwjEmoji', () => {
+ it('should gracefully handle empty string', () => {
+ expect(isPersonZwjEmoji('')).toBeFalsy();
+ });
it('should detect couple_mm', () => {
expect(isPersonZwjEmoji('👨‍❤️‍👨')).toBeTruthy();
});
@@ -300,6 +315,22 @@ describe('gl_emoji', () => {
});
describe('isEmojiUnicodeSupported', () => {
+ it('should gracefully handle empty string with unicode support', () => {
+ const isSupported = isEmojiUnicodeSupported(
+ { '1.0': true },
+ '',
+ '1.0',
+ );
+ expect(isSupported).toBeTruthy();
+ });
+ it('should gracefully handle empty string without unicode support', () => {
+ const isSupported = isEmojiUnicodeSupported(
+ {},
+ '',
+ '1.0',
+ );
+ expect(isSupported).toBeFalsy();
+ });
it('bomb(6.0) with 6.0 support', () => {
const emojiKey = 'bomb';
const unicodeSupportMap = Object.assign({}, emptySupportMap, {
diff --git a/spec/javascripts/groups/group_item_spec.js b/spec/javascripts/groups/group_item_spec.js
new file mode 100644
index 00000000000..25e10552d95
--- /dev/null
+++ b/spec/javascripts/groups/group_item_spec.js
@@ -0,0 +1,102 @@
+import Vue from 'vue';
+import groupItemComponent from '~/groups/components/group_item.vue';
+import GroupsStore from '~/groups/stores/groups_store';
+import { group1 } from './mock_data';
+
+describe('Groups Component', () => {
+ let GroupItemComponent;
+ let component;
+ let store;
+ let group;
+
+ describe('group with default data', () => {
+ beforeEach((done) => {
+ GroupItemComponent = Vue.extend(groupItemComponent);
+ store = new GroupsStore();
+ group = store.decorateGroup(group1);
+
+ component = new GroupItemComponent({
+ propsData: {
+ group,
+ },
+ }).$mount();
+
+ Vue.nextTick(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ component.$destroy();
+ });
+
+ it('should render the group item correctly', () => {
+ expect(component.$el.classList.contains('group-row')).toBe(true);
+ expect(component.$el.classList.contains('.no-description')).toBe(false);
+ expect(component.$el.querySelector('.number-projects').textContent).toContain(group.numberProjects);
+ expect(component.$el.querySelector('.number-users').textContent).toContain(group.numberUsers);
+ expect(component.$el.querySelector('.group-visibility')).toBeDefined();
+ expect(component.$el.querySelector('.avatar-container')).toBeDefined();
+ expect(component.$el.querySelector('.title').textContent).toContain(group.name);
+ expect(component.$el.querySelector('.access-type').textContent).toContain(group.permissions.humanGroupAccess);
+ expect(component.$el.querySelector('.description').textContent).toContain(group.description);
+ expect(component.$el.querySelector('.edit-group')).toBeDefined();
+ expect(component.$el.querySelector('.leave-group')).toBeDefined();
+ });
+ });
+
+ describe('group without description', () => {
+ beforeEach((done) => {
+ GroupItemComponent = Vue.extend(groupItemComponent);
+ store = new GroupsStore();
+ group1.description = '';
+ group = store.decorateGroup(group1);
+
+ component = new GroupItemComponent({
+ propsData: {
+ group,
+ },
+ }).$mount();
+
+ Vue.nextTick(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ component.$destroy();
+ });
+
+ it('should render group item correctly', () => {
+ expect(component.$el.querySelector('.description').textContent).toBe('');
+ expect(component.$el.classList.contains('.no-description')).toBe(false);
+ });
+ });
+
+ describe('user has not access to group', () => {
+ beforeEach((done) => {
+ GroupItemComponent = Vue.extend(groupItemComponent);
+ store = new GroupsStore();
+ group1.permissions.human_group_access = null;
+ group = store.decorateGroup(group1);
+
+ component = new GroupItemComponent({
+ propsData: {
+ group,
+ },
+ }).$mount();
+
+ Vue.nextTick(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ component.$destroy();
+ });
+
+ it('should not display access type', () => {
+ expect(component.$el.querySelector('.access-type')).toBeNull();
+ });
+ });
+});
diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js
new file mode 100644
index 00000000000..2a77f7259da
--- /dev/null
+++ b/spec/javascripts/groups/groups_spec.js
@@ -0,0 +1,64 @@
+import Vue from 'vue';
+import groupFolderComponent from '~/groups/components/group_folder.vue';
+import groupItemComponent from '~/groups/components/group_item.vue';
+import groupsComponent from '~/groups/components/groups.vue';
+import GroupsStore from '~/groups/stores/groups_store';
+import { groupsData } from './mock_data';
+
+describe('Groups Component', () => {
+ let GroupsComponent;
+ let store;
+ let component;
+ let groups;
+
+ beforeEach((done) => {
+ Vue.component('group-folder', groupFolderComponent);
+ Vue.component('group-item', groupItemComponent);
+
+ store = new GroupsStore();
+ groups = store.setGroups(groupsData.groups);
+
+ store.storePagination(groupsData.pagination);
+
+ GroupsComponent = Vue.extend(groupsComponent);
+
+ component = new GroupsComponent({
+ propsData: {
+ groups: store.state.groups,
+ pageInfo: store.state.pageInfo,
+ },
+ }).$mount();
+
+ Vue.nextTick(() => {
+ done();
+ });
+ });
+
+ afterEach(() => {
+ component.$destroy();
+ });
+
+ describe('with data', () => {
+ it('should render a list of groups', () => {
+ expect(component.$el.classList.contains('groups-list-tree-container')).toBe(true);
+ expect(component.$el.querySelector('#group-12')).toBeDefined();
+ expect(component.$el.querySelector('#group-1119')).toBeDefined();
+ expect(component.$el.querySelector('#group-1120')).toBeDefined();
+ });
+
+ it('should render group and its subgroup', () => {
+ const lists = component.$el.querySelectorAll('.group-list-tree');
+
+ expect(lists.length).toBe(3); // one parent and two subgroups
+
+ 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);
+ });
+
+ it('should remove prefix of parent group', () => {
+ expect(component.$el.querySelector('#group-12 #group-1128 .title').textContent).toContain('level2 / level3 / level4');
+ });
+ });
+});
diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js
new file mode 100644
index 00000000000..b3f5d791b89
--- /dev/null
+++ b/spec/javascripts/groups/mock_data.js
@@ -0,0 +1,114 @@
+const group1 = {
+ id: '12',
+ name: 'level1',
+ path: 'level1',
+ description: 'foo',
+ visibility: 'public',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/groups/level1',
+ group_path: '/level1',
+ full_name: 'level1',
+ full_path: 'level1',
+ parent_id: null,
+ created_at: '2017-05-15T19:01:23.670Z',
+ updated_at: '2017-05-15T19:01:23.670Z',
+ number_projects_with_delimiter: '1',
+ number_users_with_delimiter: '1',
+ has_subgroups: true,
+ permissions: {
+ human_group_access: 'Master',
+ },
+};
+
+// This group has no direct parent, should be placed as subgroup of group1
+const group14 = {
+ id: 1128,
+ name: 'level4',
+ path: 'level4',
+ description: 'foo',
+ visibility: 'public',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/groups/level1/level2/level3/level4',
+ group_path: '/level1/level2/level3/level4',
+ full_name: 'level1 / level2 / level3 / level4',
+ full_path: 'level1/level2/level3/level4',
+ parent_id: 1127,
+ created_at: '2017-05-15T19:02:01.645Z',
+ updated_at: '2017-05-15T19:02:01.645Z',
+ number_projects_with_delimiter: '1',
+ number_users_with_delimiter: '1',
+ has_subgroups: true,
+ permissions: {
+ human_group_access: 'Master',
+ },
+};
+
+const group2 = {
+ id: 1119,
+ name: 'devops',
+ path: 'devops',
+ description: 'foo',
+ visibility: 'public',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/groups/devops',
+ group_path: '/devops',
+ full_name: 'devops',
+ full_path: 'devops',
+ parent_id: null,
+ created_at: '2017-05-11T19:35:09.635Z',
+ updated_at: '2017-05-11T19:35:09.635Z',
+ number_projects_with_delimiter: '1',
+ number_users_with_delimiter: '1',
+ has_subgroups: true,
+ permissions: {
+ human_group_access: 'Master',
+ },
+};
+
+const group21 = {
+ id: 1120,
+ name: 'chef',
+ path: 'chef',
+ description: 'foo',
+ visibility: 'public',
+ avatar_url: null,
+ web_url: 'http://localhost:3000/groups/devops/chef',
+ group_path: '/devops/chef',
+ full_name: 'devops / chef',
+ full_path: 'devops/chef',
+ parent_id: 1119,
+ created_at: '2017-05-11T19:51:04.060Z',
+ updated_at: '2017-05-11T19:51:04.060Z',
+ number_projects_with_delimiter: '1',
+ number_users_with_delimiter: '1',
+ has_subgroups: true,
+ permissions: {
+ human_group_access: 'Master',
+ },
+};
+
+const groupsData = {
+ groups: [group1, group14, group2, group21],
+ pagination: {
+ Date: 'Mon, 22 May 2017 22:31:52 GMT',
+ 'X-Prev-Page': '1',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Total': '31',
+ 'Transfer-Encoding': 'chunked',
+ 'X-Runtime': '0.611144',
+ 'X-Xss-Protection': '1; mode=block',
+ 'X-Request-Id': 'f5db8368-3ce5-4aa4-89d2-a125d9dead09',
+ 'X-Ua-Compatible': 'IE=edge',
+ 'X-Per-Page': '20',
+ Link: '<http://localhost:3000/dashboard/groups.json?page=1&per_page=20>; rel="prev", <http://localhost:3000/dashboard/groups.json?page=1&per_page=20>; rel="first", <http://localhost:3000/dashboard/groups.json?page=2&per_page=20>; rel="last"',
+ 'X-Next-Page': '',
+ Etag: 'W/"a82f846947136271cdb7d55d19ef33d2"',
+ 'X-Frame-Options': 'DENY',
+ 'Content-Type': 'application/json; charset=utf-8',
+ 'Cache-Control': 'max-age=0, private, must-revalidate',
+ 'X-Total-Pages': '2',
+ 'X-Page': '2',
+ },
+};
+
+export { groupsData, group1 };
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index 59c006aa0af..2ccc4f16192 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -126,7 +126,7 @@ describe('Issuable output', () => {
describe('updateIssuable', () => {
it('fetches new data after update', (done) => {
- spyOn(vm.service, 'getData');
+ spyOn(vm.service, 'getData').and.callThrough();
spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => {
resolve({
json() {
diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js
new file mode 100644
index 00000000000..c7179b3e03d
--- /dev/null
+++ b/spec/javascripts/jobs/header_spec.js
@@ -0,0 +1,63 @@
+import Vue from 'vue';
+import headerComponent from '~/jobs/components/header.vue';
+
+describe('Job details header', () => {
+ let HeaderComponent;
+ let vm;
+ let props;
+
+ beforeEach(() => {
+ HeaderComponent = Vue.extend(headerComponent);
+
+ const threeWeeksAgo = new Date();
+ threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+
+ props = {
+ job: {
+ status: {
+ group: 'failed',
+ icon: 'ci-status-failed',
+ label: 'failed',
+ text: 'failed',
+ details_path: 'path',
+ },
+ id: 123,
+ created_at: threeWeeksAgo.toISOString(),
+ user: {
+ web_url: 'path',
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatar_url: 'link',
+ },
+ retry_path: 'path',
+ new_issue_path: 'path',
+ },
+ isLoading: false,
+ };
+
+ vm = new HeaderComponent({ propsData: props }).$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should render provided job information', () => {
+ expect(
+ vm.$el.querySelector('.header-main-content').textContent.replace(/\s+/g, ' ').trim(),
+ ).toEqual('failed Job #123 triggered 3 weeks ago by Foo');
+ });
+
+ it('should render retry link', () => {
+ expect(
+ vm.$el.querySelector('.js-retry-button').getAttribute('href'),
+ ).toEqual(props.job.retry_path);
+ });
+
+ it('should render new issue link', () => {
+ expect(
+ vm.$el.querySelector('.js-new-issue').getAttribute('href'),
+ ).toEqual(props.job.new_issue_path);
+ });
+});
diff --git a/spec/javascripts/jobs/job_details_mediator_spec.js b/spec/javascripts/jobs/job_details_mediator_spec.js
new file mode 100644
index 00000000000..1d7fa7e12fc
--- /dev/null
+++ b/spec/javascripts/jobs/job_details_mediator_spec.js
@@ -0,0 +1,43 @@
+import Vue from 'vue';
+import JobMediator from '~/jobs/job_details_mediator';
+import job from './mock_data';
+
+describe('JobMediator', () => {
+ let mediator;
+
+ beforeEach(() => {
+ mediator = new JobMediator({ endpoint: 'foo' });
+ });
+
+ it('should set defaults', () => {
+ expect(mediator.store).toBeDefined();
+ expect(mediator.service).toBeDefined();
+ expect(mediator.options).toEqual({ endpoint: 'foo' });
+ expect(mediator.state.isLoading).toEqual(false);
+ });
+
+ describe('request and store data', () => {
+ const interceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(job), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptor, interceptor);
+ });
+
+ it('should store received data', (done) => {
+ mediator.fetchJob();
+
+ setTimeout(() => {
+ expect(mediator.store.state.job).toEqual(job);
+ done();
+ }, 0);
+ });
+ });
+});
diff --git a/spec/javascripts/jobs/job_store_spec.js b/spec/javascripts/jobs/job_store_spec.js
new file mode 100644
index 00000000000..d00faf29d1e
--- /dev/null
+++ b/spec/javascripts/jobs/job_store_spec.js
@@ -0,0 +1,26 @@
+import JobStore from '~/jobs/stores/job_store';
+import job from './mock_data';
+
+describe('Job Store', () => {
+ let store;
+
+ beforeEach(() => {
+ store = new JobStore();
+ });
+
+ it('should set defaults', () => {
+ expect(store.state.job).toEqual({});
+ });
+
+ describe('storeJob', () => {
+ it('should store empty object if none is provided', () => {
+ store.storeJob();
+ expect(store.state.job).toEqual({});
+ });
+
+ it('should store provided argument', () => {
+ store.storeJob(job);
+ expect(store.state.job).toEqual(job);
+ });
+ });
+});
diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js
new file mode 100644
index 00000000000..17e4ef26b2c
--- /dev/null
+++ b/spec/javascripts/jobs/mock_data.js
@@ -0,0 +1,123 @@
+const threeWeeksAgo = new Date();
+threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+
+export default {
+ id: 4757,
+ name: 'test',
+ build_path: '/root/ci-mock/-/jobs/4757',
+ retry_path: '/root/ci-mock/-/jobs/4757/retry',
+ cancel_path: '/root/ci-mock/-/jobs/4757/cancel',
+ new_issue_path: '/root/ci-mock/issues/new',
+ playable: false,
+ created_at: threeWeeksAgo.toISOString(),
+ updated_at: threeWeeksAgo.toISOString(),
+ finished_at: threeWeeksAgo.toISOString(),
+ queued: 9.54,
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ has_details: true,
+ details_path: '/root/ci-mock/-/jobs/4757',
+ favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
+ action: {
+ icon: 'icon_action_retry',
+ title: 'Retry',
+ path: '/root/ci-mock/-/jobs/4757/retry',
+ method: 'post',
+ },
+ },
+ coverage: 20,
+ erased_at: threeWeeksAgo.toISOString(),
+ duration: 6.785563,
+ tags: ['tag'],
+ user: {
+ name: 'Root',
+ username: 'root',
+ id: 1,
+ state: 'active',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3000/root',
+ },
+ erase_path: '/root/ci-mock/-/jobs/4757/erase',
+ artifacts: [null],
+ runner: {
+ id: 1,
+ description: 'local ci runner',
+ edit_path: '/root/ci-mock/runners/1/edit',
+ },
+ pipeline: {
+ id: 140,
+ user: {
+ name: 'Root',
+ username: 'root',
+ id: 1,
+ state: 'active',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3000/root',
+ },
+ active: false,
+ coverage: null,
+ source: 'unknown',
+ created_at: '2017-05-24T09:59:58.634Z',
+ updated_at: '2017-06-01T17:32:00.062Z',
+ path: '/root/ci-mock/pipelines/140',
+ flags: {
+ latest: true,
+ stuck: false,
+ yaml_errors: false,
+ retryable: false,
+ cancelable: false,
+ },
+ details: {
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ has_details: true,
+ details_path: '/root/ci-mock/pipelines/140',
+ favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico',
+ },
+ duration: 6,
+ finished_at: '2017-06-01T17:32:00.042Z',
+ },
+ ref: {
+ name: 'abc',
+ path: '/root/ci-mock/commits/abc',
+ tag: false,
+ branch: true,
+ },
+ commit: {
+ id: 'c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
+ short_id: 'c5864777',
+ title: 'Add new file',
+ created_at: '2017-05-24T10:59:52.000+01:00',
+ parent_ids: ['798e5f902592192afaba73f4668ae30e56eae492'],
+ message: 'Add new file',
+ author_name: 'Root',
+ author_email: 'admin@example.com',
+ authored_date: '2017-05-24T10:59:52.000+01:00',
+ committer_name: 'Root',
+ committer_email: 'admin@example.com',
+ committed_date: '2017-05-24T10:59:52.000+01:00',
+ author: {
+ name: 'Root',
+ username: 'root',
+ id: 1,
+ state: 'active',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ web_url: 'http://localhost:3000/root',
+ },
+ author_gravatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
+ commit_url: 'http://localhost:3000/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
+ commit_path: '/root/ci-mock/commit/c58647773a6b5faf066d4ad6ff2c9fbba5f180f6',
+ },
+ },
+ merge_request: {
+ iid: 2,
+ path: '/root/ci-mock/merge_requests/2',
+ },
+ raw_path: '/root/ci-mock/builds/4757/raw',
+};
diff --git a/spec/javascripts/jobs/sidebar_detail_row_spec.js b/spec/javascripts/jobs/sidebar_detail_row_spec.js
new file mode 100644
index 00000000000..3ac65709c4a
--- /dev/null
+++ b/spec/javascripts/jobs/sidebar_detail_row_spec.js
@@ -0,0 +1,40 @@
+import Vue from 'vue';
+import sidebarDetailRow from '~/jobs/components/sidebar_detail_row.vue';
+
+describe('Sidebar detail row', () => {
+ let SidebarDetailRow;
+ let vm;
+
+ beforeEach(() => {
+ SidebarDetailRow = Vue.extend(sidebarDetailRow);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should render no title', () => {
+ vm = new SidebarDetailRow({
+ propsData: {
+ value: 'this is the value',
+ },
+ }).$mount();
+
+ expect(vm.$el.textContent.replace(/\s+/g, ' ').trim()).toEqual('this is the value');
+ });
+
+ beforeEach(() => {
+ vm = new SidebarDetailRow({
+ propsData: {
+ title: 'this is the title',
+ value: 'this is the value',
+ },
+ }).$mount();
+ });
+
+ it('should render provided title and value', () => {
+ expect(
+ vm.$el.textContent.replace(/\s+/g, ' ').trim(),
+ ).toEqual('this is the title: this is the value');
+ });
+});
diff --git a/spec/javascripts/jobs/sidebar_details_block_spec.js b/spec/javascripts/jobs/sidebar_details_block_spec.js
new file mode 100644
index 00000000000..95532ef5382
--- /dev/null
+++ b/spec/javascripts/jobs/sidebar_details_block_spec.js
@@ -0,0 +1,111 @@
+import Vue from 'vue';
+import sidebarDetailsBlock from '~/jobs/components/sidebar_details_block.vue';
+import job from './mock_data';
+
+describe('Sidebar details block', () => {
+ let SidebarComponent;
+ let vm;
+
+ function trimWhitespace(element) {
+ return element.textContent.replace(/\s+/g, ' ').trim();
+ }
+
+ beforeEach(() => {
+ SidebarComponent = Vue.extend(sidebarDetailsBlock);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('when it is loading', () => {
+ it('should render a loading spinner', () => {
+ vm = new SidebarComponent({
+ propsData: {
+ job: {},
+ isLoading: true,
+ },
+ }).$mount();
+
+ expect(vm.$el.querySelector('.fa-spinner')).toBeDefined();
+ });
+ });
+
+ beforeEach(() => {
+ vm = new SidebarComponent({
+ propsData: {
+ job,
+ isLoading: false,
+ },
+ }).$mount();
+ });
+
+ describe('actions', () => {
+ it('should render link to new issue', () => {
+ expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual(job.new_issue_path);
+ expect(vm.$el.querySelector('.js-new-issue').textContent.trim()).toEqual('New issue');
+ });
+
+ it('should render link to retry job', () => {
+ expect(vm.$el.querySelector('.js-retry-job').getAttribute('href')).toEqual(job.retry_path);
+ });
+
+ it('should render link to cancel job', () => {
+ expect(vm.$el.querySelector('.js-cancel-job').getAttribute('href')).toEqual(job.cancel_path);
+ });
+ });
+
+ describe('information', () => {
+ it('should render merge request link', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-mr')),
+ ).toEqual('Merge Request: !2');
+
+ expect(
+ vm.$el.querySelector('.js-job-mr a').getAttribute('href'),
+ ).toEqual(job.merge_request.path);
+ });
+
+ it('should render job duration', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-duration')),
+ ).toEqual('Duration: 6 seconds');
+ });
+
+ it('should render erased date', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-erased')),
+ ).toEqual('Erased: 3 weeks ago');
+ });
+
+ it('should render finished date', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-finished')),
+ ).toEqual('Finished: 3 weeks ago');
+ });
+
+ it('should render queued date', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-queued')),
+ ).toEqual('Queued: 9 seconds');
+ });
+
+ it('should render runner ID', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-runner')),
+ ).toEqual('Runner: #1');
+ });
+
+ it('should render coverage', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-coverage')),
+ ).toEqual('Coverage: 20%');
+ });
+
+ it('should render tags', () => {
+ expect(
+ trimWhitespace(vm.$el.querySelector('.js-job-tags')),
+ ).toEqual('Tags: tag');
+ });
+ });
+});
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index e3938a77680..52cf217c25f 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -150,6 +150,14 @@ import '~/lib/utils/common_utils';
const value = gl.utils.getParameterByName('fakeParameter');
expect(value).toBe(null);
});
+
+ it('should return valid paramentes if URL is provided', () => {
+ let value = gl.utils.getParameterByName('foo', 'http://cocteau.twins/?foo=bar');
+ expect(value).toBe('bar');
+
+ value = gl.utils.getParameterByName('manan', 'http://cocteau.twins/?foo=bar&manan=canchu');
+ expect(value).toBe('canchu');
+ });
});
describe('gl.utils.normalizedHeaders', () => {
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index 7b910282cc8..9916d2c1e21 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -12,15 +12,6 @@ import '~/notes';
import 'vendor/jquery.scrollTo';
(function () {
- // TODO: remove this hack!
- // PhantomJS causes spyOn to panic because replaceState isn't "writable"
- var phantomjs;
- try {
- phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable;
- } catch (err) {
- phantomjs = false;
- }
-
describe('MergeRequestTabs', function () {
var stubLocation = {};
var setLocation = function (stubs) {
@@ -37,11 +28,9 @@ import 'vendor/jquery.scrollTo';
this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation });
setLocation();
- if (!phantomjs) {
- this.spies = {
- history: spyOn(window.history, 'replaceState').and.callFake(function () {})
- };
- }
+ this.spies = {
+ history: spyOn(window.history, 'replaceState').and.callFake(function () {})
+ };
});
afterEach(function () {
@@ -208,11 +197,9 @@ import 'vendor/jquery.scrollTo';
pathname: '/foo/bar/merge_requests/1'
});
newState = this.subject('commits');
- if (!phantomjs) {
- expect(this.spies.history).toHaveBeenCalledWith({
- url: newState
- }, document.title, newState);
- }
+ expect(this.spies.history).toHaveBeenCalledWith({
+ url: newState
+ }, document.title, newState);
});
it('treats "show" like "notes"', function () {
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index 24335614e09..c6f218e4dac 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -126,6 +126,7 @@ import '~/notes';
const deferred = $.Deferred();
spyOn($, 'ajax').and.returnValue(deferred.promise());
spyOn(this.notes, 'revertNoteEditForm');
+ spyOn(this.notes, 'setupNewNote');
$('.js-comment-button').click();
deferred.resolve(noteEntity);
@@ -136,6 +137,46 @@ import '~/notes';
this.notes.updateNote(updatedNote, $targetNote);
expect(this.notes.revertNoteEditForm).toHaveBeenCalledWith($targetNote);
+ expect(this.notes.setupNewNote).toHaveBeenCalled();
+ });
+ });
+
+ describe('updateNoteTargetSelector', () => {
+ const hash = 'note_foo';
+ let $note;
+
+ beforeEach(() => {
+ $note = $(`<div id="${hash}"></div>`);
+ spyOn($note, 'filter').and.callThrough();
+ spyOn($note, 'toggleClass').and.callThrough();
+ });
+
+ it('sets target when hash matches', () => {
+ spyOn(gl.utils, 'getLocationHash');
+ gl.utils.getLocationHash.and.returnValue(hash);
+
+ Notes.updateNoteTargetSelector($note);
+
+ expect($note.filter).toHaveBeenCalledWith(`#${hash}`);
+ expect($note.toggleClass).toHaveBeenCalledWith('target', true);
+ });
+
+ it('unsets target when hash does not match', () => {
+ spyOn(gl.utils, 'getLocationHash');
+ gl.utils.getLocationHash.and.returnValue('note_doesnotexist');
+
+ Notes.updateNoteTargetSelector($note);
+
+ expect($note.toggleClass).toHaveBeenCalledWith('target', false);
+ });
+
+ it('unsets target when there is not a hash fragment anymore', () => {
+ spyOn(gl.utils, 'getLocationHash');
+ gl.utils.getLocationHash.and.returnValue(null);
+
+ Notes.updateNoteTargetSelector($note);
+
+ expect($note.toggleClass).toHaveBeenCalledWith('target', null);
});
});
@@ -189,9 +230,13 @@ import '~/notes';
Notes.isUpdatedNote.and.returnValue(true);
const $note = $('<div>');
$notesList.find.and.returnValue($note);
+ const $newNote = $(note.html);
+ Notes.animateUpdateNote.and.returnValue($newNote);
+
Notes.prototype.renderNote.call(notes, note, null, $notesList);
expect(Notes.animateUpdateNote).toHaveBeenCalledWith(note.html, $note);
+ expect(notes.setupNewNote).toHaveBeenCalledWith($newNote);
});
describe('while editing', () => {
@@ -378,6 +423,23 @@ import '~/notes';
});
});
+ describe('putEditFormInPlace', () => {
+ it('should call gl.GLForm with GFM parameter passed through', () => {
+ spyOn(gl, 'GLForm');
+
+ const $el = jasmine.createSpyObj('$form', ['find', 'closest']);
+ $el.find.and.returnValue($('<div>'));
+ $el.closest.and.returnValue($('<div>'));
+
+ Notes.prototype.putEditFormInPlace.call({
+ getEditFormSelector: () => '',
+ enableGFM: true
+ }, $el);
+
+ expect(gl.GLForm).toHaveBeenCalledWith(jasmine.any(Object), true);
+ });
+ });
+
describe('postComment & updateComment', () => {
const sampleComment = 'foo';
const updatedComment = 'bar';
@@ -461,6 +523,45 @@ import '~/notes';
});
});
+ describe('update comment with script tags', () => {
+ const sampleComment = '<script></script>';
+ const updatedComment = '<script></script>';
+ const note = {
+ id: 1234,
+ html: `<li class="note note-row-1234 timeline-entry" id="note_1234">
+ <div class="note-text">${sampleComment}</div>
+ </li>`,
+ note: sampleComment,
+ valid: true
+ };
+ let $form;
+ let $notesContainer;
+
+ beforeEach(() => {
+ this.notes = new Notes('', []);
+ window.gon.current_username = 'root';
+ window.gon.current_user_fullname = 'Administrator';
+ $form = $('form.js-main-target-form');
+ $notesContainer = $('ul.main-notes-list');
+ $form.find('textarea.js-note-text').html(sampleComment);
+ });
+
+ it('should not render a script tag', () => {
+ const deferred = $.Deferred();
+ spyOn($, 'ajax').and.returnValue(deferred.promise());
+ $('.js-comment-button').click();
+
+ deferred.resolve(note);
+ const $noteEl = $notesContainer.find(`#note_${note.id}`);
+ $noteEl.find('.js-note-edit').click();
+ $noteEl.find('textarea.js-note-text').html(updatedComment);
+ $noteEl.find('.js-comment-save-button').click();
+
+ const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`).find('.js-task-list-container');
+ expect($updatedNoteEl.find('.note-text').text().trim()).toEqual('');
+ });
+ });
+
describe('getFormData', () => {
let $form;
let sampleComment;
diff --git a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js b/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
index 845b371d90c..56c57d94798 100644
--- a/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
+++ b/spec/javascripts/pipeline_schedules/interval_pattern_input_spec.js
@@ -95,7 +95,7 @@ describe('Interval Pattern Input Component', function () {
describe('User Actions', function () {
beforeEach(function () {
- // For an unknown reason, Phantom.js doesn't trigger click events
+ // For an unknown reason, some browsers do not propagate click events
// on radio buttons in a way Vue can register. So, we have to mount
// to a fixture.
setFixtures('<div id="my-mount"></div>');
diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js
index 601eebce38a..f1697840fcd 100644
--- a/spec/javascripts/pipelines/nav_controls_spec.js
+++ b/spec/javascripts/pipelines/nav_controls_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import navControlsComp from '~/pipelines/components/nav_controls';
+import navControlsComp from '~/pipelines/components/nav_controls.vue';
describe('Pipelines Nav Controls', () => {
let NavControlsComponent;
diff --git a/spec/javascripts/pipelines/pipeline_url_spec.js b/spec/javascripts/pipelines/pipeline_url_spec.js
index 594a9856d2c..3c4b20a5f06 100644
--- a/spec/javascripts/pipelines/pipeline_url_spec.js
+++ b/spec/javascripts/pipelines/pipeline_url_spec.js
@@ -19,7 +19,7 @@ describe('Pipeline Url Component', () => {
},
}).$mount();
- expect(component.$el.tagName).toEqual('TD');
+ expect(component.$el.getAttribute('class')).toContain('table-section');
});
it('should render a link the provided path and id', () => {
@@ -94,7 +94,7 @@ describe('Pipeline Url Component', () => {
},
}).$mount();
- expect(component.$el.querySelector('.js-pipeline-url-lastest').textContent).toContain('latest');
+ expect(component.$el.querySelector('.js-pipeline-url-latest').textContent).toContain('latest');
expect(component.$el.querySelector('.js-pipeline-url-yaml').textContent).toContain('yaml invalid');
expect(component.$el.querySelector('.js-pipeline-url-stuck').textContent).toContain('stuck');
});
diff --git a/spec/javascripts/pipelines/pipelines_actions_spec.js b/spec/javascripts/pipelines/pipelines_actions_spec.js
index c89dacbcd93..8a58b77f1e3 100644
--- a/spec/javascripts/pipelines/pipelines_actions_spec.js
+++ b/spec/javascripts/pipelines/pipelines_actions_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import pipelinesActionsComp from '~/pipelines/components/pipelines_actions';
+import pipelinesActionsComp from '~/pipelines/components/pipelines_actions.vue';
describe('Pipelines Actions dropdown', () => {
let component;
diff --git a/spec/javascripts/pipelines/pipelines_artifacts_spec.js b/spec/javascripts/pipelines/pipelines_artifacts_spec.js
index 9724b63d957..acb67d0ec21 100644
--- a/spec/javascripts/pipelines/pipelines_artifacts_spec.js
+++ b/spec/javascripts/pipelines/pipelines_artifacts_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import artifactsComp from '~/pipelines/components/pipelines_artifacts';
+import artifactsComp from '~/pipelines/components/pipelines_artifacts.vue';
describe('Pipelines Artifacts dropdown', () => {
let component;
diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js
index 3a56156358b..c30abb2edb0 100644
--- a/spec/javascripts/pipelines/pipelines_spec.js
+++ b/spec/javascripts/pipelines/pipelines_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import pipelinesComp from '~/pipelines/pipelines';
+import pipelinesComp from '~/pipelines/components/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store';
describe('Pipelines', () => {
diff --git a/spec/javascripts/pipelines/time_ago_spec.js b/spec/javascripts/pipelines/time_ago_spec.js
index 24581e8c672..42b34c82f89 100644
--- a/spec/javascripts/pipelines/time_ago_spec.js
+++ b/spec/javascripts/pipelines/time_ago_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import timeAgo from '~/pipelines/components/time_ago';
+import timeAgo from '~/pipelines/components/time_ago.vue';
describe('Timeago component', () => {
let TimeAgo;
diff --git a/spec/javascripts/pipelines_spec.js b/spec/javascripts/pipelines_spec.js
index 81ac589f4e6..c08a73851be 100644
--- a/spec/javascripts/pipelines_spec.js
+++ b/spec/javascripts/pipelines_spec.js
@@ -1,10 +1,5 @@
import Pipelines from '~/pipelines';
-// Fix for phantomJS
-if (!Element.prototype.matches && Element.prototype.webkitMatchesSelector) {
- Element.prototype.matches = Element.prototype.webkitMatchesSelector;
-}
-
describe('Pipelines', () => {
preloadFixtures('static/pipeline_graph.html.raw');
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 13827a26571..2c34402576b 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -51,7 +51,6 @@ if (process.env.BABEL_ENV === 'coverage') {
'./environments/environments_bundle.js',
'./filtered_search/filtered_search_bundle.js',
'./graphs/graphs_bundle.js',
- './issuable/issuable_bundle.js',
'./issuable/time_tracking/time_tracking_bundle.js',
'./main.js',
'./merge_conflicts/merge_conflicts_bundle.js',
diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js
index 050170a54e9..1c3188cdda2 100644
--- a/spec/javascripts/vue_shared/components/commit_spec.js
+++ b/spec/javascripts/vue_shared/components/commit_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import commitComp from '~/vue_shared/components/commit';
+import commitComp from '~/vue_shared/components/commit.vue';
describe('Commit component', () => {
let props;
@@ -22,7 +22,7 @@ describe('Commit component', () => {
shortSha: 'b7836edd',
title: 'Commit message',
author: {
- avatar_url: 'https://gitlab.com/uploads/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/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/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
index 2b51c89f311..b4553acb341 100644
--- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js
+++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js
@@ -43,6 +43,7 @@ describe('Header CI Component', () => {
isLoading: false,
},
],
+ hasSidebarButton: true,
};
vm = new HeaderCi({
@@ -86,8 +87,12 @@ describe('Header CI Component', () => {
vm.actions[0].isLoading = true;
Vue.nextTick(() => {
- expect(vm.$el.querySelector('.btn .fa-spinner').getAttribute('style')).toEqual('');
+ expect(vm.$el.querySelector('.btn .fa-spinner').getAttribute('style')).toBeFalsy();
done();
});
});
+
+ it('should render sidebar toggle button', () => {
+ expect(vm.$el.querySelector('.js-sidebar-build-toggle')).toBeDefined();
+ });
});
diff --git a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
index 67419cfcbea..9475ee28a03 100644
--- a/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
+++ b/spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import tableRowComp from '~/vue_shared/components/pipelines_table_row';
+import tableRowComp from '~/vue_shared/components/pipelines_table_row.vue';
describe('Pipelines Table Row', () => {
const jsonFixtureName = 'pipelines/pipelines.json';
@@ -34,7 +34,7 @@ describe('Pipelines Table Row', () => {
it('should render a table row', () => {
component = buildComponent(pipeline);
- expect(component.$el).toEqual('TR');
+ expect(component.$el.getAttribute('class')).toContain('gl-responsive-table-row');
});
describe('status column', () => {
@@ -44,13 +44,13 @@ describe('Pipelines Table Row', () => {
it('should render a pipeline link', () => {
expect(
- component.$el.querySelector('td.commit-link a').getAttribute('href'),
+ component.$el.querySelector('.table-section.commit-link a').getAttribute('href'),
).toEqual(pipeline.path);
});
it('should render status text', () => {
expect(
- component.$el.querySelector('td.commit-link a').textContent,
+ component.$el.querySelector('.table-section.commit-link a').textContent,
).toContain(pipeline.details.status.text);
});
});
@@ -62,24 +62,24 @@ describe('Pipelines Table Row', () => {
it('should render a pipeline link', () => {
expect(
- component.$el.querySelector('td:nth-child(2) a').getAttribute('href'),
+ component.$el.querySelector('.table-section:nth-child(2) a').getAttribute('href'),
).toEqual(pipeline.path);
});
it('should render pipeline ID', () => {
expect(
- component.$el.querySelector('td:nth-child(2) a > span').textContent,
+ component.$el.querySelector('.table-section:nth-child(2) a > span').textContent,
).toEqual(`#${pipeline.id}`);
});
describe('when a user is provided', () => {
it('should render user information', () => {
expect(
- component.$el.querySelector('td:nth-child(2) a:nth-child(3)').getAttribute('href'),
+ component.$el.querySelector('.table-section:nth-child(2) a:nth-child(3)').getAttribute('href'),
).toEqual(pipeline.user.path);
expect(
- component.$el.querySelector('td:nth-child(2) img').getAttribute('data-original-title'),
+ component.$el.querySelector('.table-section:nth-child(2) img').getAttribute('data-original-title'),
).toEqual(pipeline.user.name);
});
});
@@ -142,7 +142,7 @@ describe('Pipelines Table Row', () => {
it('should render an icon for each stage', () => {
expect(
- component.$el.querySelectorAll('td:nth-child(4) .js-builds-dropdown-button').length,
+ component.$el.querySelectorAll('.table-section:nth-child(4) .js-builds-dropdown-button').length,
).toEqual(pipeline.details.stages.length);
});
});
@@ -154,7 +154,7 @@ describe('Pipelines Table Row', () => {
it('should render the provided actions', () => {
expect(
- component.$el.querySelectorAll('td:nth-child(6) ul li').length,
+ component.$el.querySelectorAll('.table-section:nth-child(6) ul li').length,
).toEqual(pipeline.details.manual_actions.length);
});
});
diff --git a/spec/javascripts/vue_shared/components/pipelines_table_spec.js b/spec/javascripts/vue_shared/components/pipelines_table_spec.js
index 6cc178b8f1d..4c35d702004 100644
--- a/spec/javascripts/vue_shared/components/pipelines_table_spec.js
+++ b/spec/javascripts/vue_shared/components/pipelines_table_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import pipelinesTableComp from '~/vue_shared/components/pipelines_table';
+import pipelinesTableComp from '~/vue_shared/components/pipelines_table.vue';
import '~/lib/utils/datetime_utility';
describe('Pipelines Table', () => {
@@ -32,16 +32,14 @@ describe('Pipelines Table', () => {
});
it('should render a table', () => {
- expect(component.$el).toEqual('TABLE');
+ expect(component.$el.getAttribute('class')).toContain('ci-table');
});
it('should render table head with correct columns', () => {
- expect(component.$el.querySelector('th.js-pipeline-status').textContent).toEqual('Status');
- expect(component.$el.querySelector('th.js-pipeline-info').textContent).toEqual('Pipeline');
- expect(component.$el.querySelector('th.js-pipeline-commit').textContent).toEqual('Commit');
- expect(component.$el.querySelector('th.js-pipeline-stages').textContent).toEqual('Stages');
- expect(component.$el.querySelector('th.js-pipeline-date').textContent).toEqual('');
- expect(component.$el.querySelector('th.js-pipeline-actions').textContent).toEqual('');
+ expect(component.$el.querySelector('.table-section.js-pipeline-status').textContent.trim()).toEqual('Status');
+ expect(component.$el.querySelector('.table-section.js-pipeline-info').textContent.trim()).toEqual('Pipeline');
+ expect(component.$el.querySelector('.table-section.js-pipeline-commit').textContent.trim()).toEqual('Commit');
+ expect(component.$el.querySelector('.table-section.js-pipeline-stages').textContent.trim()).toEqual('Stages');
});
});
@@ -53,7 +51,7 @@ describe('Pipelines Table', () => {
service: {},
},
}).$mount();
- expect(component.$el.querySelectorAll('tbody tr').length).toEqual(0);
+ expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(0);
});
});
@@ -67,7 +65,7 @@ describe('Pipelines Table', () => {
},
}).$mount();
- expect(component.$el.querySelectorAll('tbody tr').length).toEqual(1);
+ expect(component.$el.querySelectorAll('.commit.gl-responsive-table-row').length).toEqual(1);
});
});
});
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 bf28019ef24..f3b4adc0b70 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,7 @@ describe('Time ago with tooltip component', () => {
}).$mount();
expect(vm.$el.tagName).toEqual('TIME');
- expect(vm.$el.classList.contains('js-timeago')).toEqual(true);
+ 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'));
@@ -44,17 +44,6 @@ describe('Time ago with tooltip component', () => {
expect(vm.$el.getAttribute('data-placement')).toEqual('bottom');
});
- it('should render short format class', () => {
- vm = new TimeagoTooltip({
- propsData: {
- time: '2017-05-08T14:57:39.781Z',
- shortFormat: true,
- },
- }).$mount();
-
- expect(vm.$el.classList.contains('js-short-timeago')).toEqual(true);
- });
-
it('should render provided html class', () => {
vm = new TimeagoTooltip({
propsData: {
diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
index 27684882435..787c2372c5b 100644
--- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb
@@ -47,16 +47,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
end
end
- context 'with RequestStore enabled' do
- before do
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
- end
-
+ context 'with RequestStore enabled', :request_store do
it 'returns a list of Projects for a list of paths' do
expect(filter.find_projects_for_paths([project.path_with_namespace])).
to eq([project])
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 fbf7a461fa5..76cefe112fb 100644
--- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -82,7 +82,9 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
context 'with RequestStore enabled' do
let(:reference_filter) { HTML::Pipeline.new([described_class]) }
- before { allow(RequestStore).to receive(:active?).and_return(true) }
+ before do
+ allow(RequestStore).to receive(:active?).and_return(true)
+ end
it 'queries the collection on the first call' do
expect_any_instance_of(Project).to receive(:default_issues_tracker?).once.and_call_original
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index 7c4a0f32c7b..97504aebed5 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -39,7 +39,9 @@ describe Banzai::Filter::RedactorFilter, lib: true do
end
context 'valid projects' do
- before { allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true) }
+ before do
+ allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(true)
+ end
it 'allows permitted Project references' do
user = create(:user)
@@ -54,7 +56,9 @@ describe Banzai::Filter::RedactorFilter, lib: true do
end
context 'invalid projects' do
- before { allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false) }
+ before do
+ allow_any_instance_of(Banzai::ReferenceParser::BaseParser).to receive(:can_read_reference?).and_return(false)
+ end
it 'removes unpermitted references' do
user = create(:user)
diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb
index e5d332efb08..866297f94a9 100644
--- a/spec/lib/banzai/issuable_extractor_spec.rb
+++ b/spec/lib/banzai/issuable_extractor_spec.rb
@@ -29,16 +29,7 @@ describe Banzai::IssuableExtractor, lib: true do
expect(result).to eq(issue_link => issue, merge_request_link => merge_request)
end
- describe 'caching' do
- before do
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
- end
-
+ describe 'caching', :request_store do
it 'saves records to cache' do
extractor.extract([issue_link, merge_request_link])
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index d5746107ee1..76fab93821a 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -30,7 +30,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do
it 'checks if user can read the resource' do
link['data-project'] = project.id.to_s
- expect(subject).to receive(:can_read_reference?).with(user, project)
+ expect(subject).to receive(:can_read_reference?).with(user, project, link)
subject.nodes_visible_to_user(user, [link])
end
@@ -114,7 +114,7 @@ describe Banzai::ReferenceParser::BaseParser, lib: true do
expect(hash).to eq({ link => user })
end
- it 'returns an empty Hash when entry does not exist in the database' do
+ it 'returns an empty Hash when entry does not exist in the database', :request_store do
link = double(:link)
expect(link).to receive(:has_attribute?).
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
index 412ffa77c36..583ce63a8ab 100644
--- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::CommitParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-commit'] = 123 }
+ before do
+ link['data-commit'] = 123
+ end
it_behaves_like "referenced feature visibility", "repository"
end
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 96e55b0997a..8c0f5d7df97 100644
--- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::CommitRangeParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-commit-range'] = '123..456' }
+ before do
+ link['data-commit-range'] = '123..456'
+ end
it_behaves_like "referenced feature visibility", "repository"
end
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 0af36776a54..d212bbac619 100644
--- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -10,7 +10,9 @@ describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-external-issue'] = 123 }
+ before do
+ link['data-external-issue'] = 123
+ end
levels = [ProjectFeature::DISABLED, ProjectFeature::PRIVATE, ProjectFeature::ENABLED]
diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb
index 8c540d35ddd..ddd699f3c25 100644
--- a/spec/lib/banzai/reference_parser/label_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb
@@ -11,7 +11,9 @@ describe Banzai::ReferenceParser::LabelParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-label'] = label.id.to_s }
+ before do
+ link['data-label'] = label.id.to_s
+ end
it_behaves_like "referenced feature visibility", "issues", "merge_requests"
end
diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
index 2d4d589ae34..72d4f3bc18e 100644
--- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
@@ -11,7 +11,9 @@ describe Banzai::ReferenceParser::MilestoneParser, lib: true do
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- before { link['data-milestone'] = milestone.id.to_s }
+ before do
+ link['data-milestone'] = milestone.id.to_s
+ end
it_behaves_like "referenced feature visibility", "issues", "merge_requests"
end
diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
index d217a775802..620875ece20 100644
--- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
@@ -4,20 +4,199 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do
include ReferenceParserHelpers
let(:project) { create(:empty_project, :public) }
+
let(:user) { create(:user) }
- let(:snippet) { create(:snippet, project: project) }
+ let(:external_user) { create(:user, :external) }
+ let(:project_member) { create(:user) }
+
subject { described_class.new(project, user) }
let(:link) { empty_html_link }
+ def visible_references(snippet_visibility, user = nil)
+ snippet = create(:project_snippet, snippet_visibility, project: project)
+ link['data-project'] = project.id.to_s
+ link['data-snippet'] = snippet.id.to_s
+
+ subject.nodes_visible_to_user(user, [link])
+ end
+
+ before do
+ project.add_user(project_member, :developer)
+ end
+
describe '#nodes_visible_to_user' do
- context 'when the link has a data-issue attribute' do
- before { link['data-snippet'] = snippet.id.to_s }
+ context 'when a project is public and the snippets feature is enabled for everyone' do
+ before do
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED)
+ end
+
+ it 'creates a reference for guest for a public snippet' do
+ expect(visible_references(:public)).to eq([link])
+ end
+
+ it 'creates a reference for a regular user for a public snippet' do
+ expect(visible_references(:public, user)).to eq([link])
+ end
+
+ it 'creates a reference for a regular user for an internal snippet' do
+ expect(visible_references(:internal, user)).to eq([link])
+ end
+
+ it 'does not create a reference for an external user for an internal snippet' do
+ expect(visible_references(:internal, external_user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for a private snippet' do
+ expect(visible_references(:private, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for a private snippet' do
+ expect(visible_references(:private, user)).to be_empty
+ end
+ end
+
+ context 'when a project is public and the snippets feature is enabled for project team members' do
+ before do
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE)
+ end
+
+ it 'creates a reference for a project member for a public snippet' do
+ expect(visible_references(:public, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for guest for a public snippet' do
+ expect(visible_references(:public, nil)).to be_empty
+ end
+
+ it 'does not create a reference for a regular user for a public snippet' do
+ expect(visible_references(:public, user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for an internal snippet' do
+ expect(visible_references(:internal, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for an internal snippet' do
+ expect(visible_references(:internal, user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for a private snippet' do
+ expect(visible_references(:private, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for a private snippet' do
+ expect(visible_references(:private, user)).to be_empty
+ end
+ end
+
+ context 'when a project is internal and the snippets feature is enabled for everyone' do
+ before do
+ project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL)
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::ENABLED)
+ end
+
+ it 'does not create a reference for guest for a public snippet' do
+ expect(visible_references(:public)).to be_empty
+ end
+
+ it 'does not create a reference for an external user for a public snippet' do
+ expect(visible_references(:public, external_user)).to be_empty
+ end
- it_behaves_like "referenced feature visibility", "snippets"
+ it 'creates a reference for a regular user for a public snippet' do
+ expect(visible_references(:public, user)).to eq([link])
+ end
+
+ it 'creates a reference for a regular user for an internal snippet' do
+ expect(visible_references(:internal, user)).to eq([link])
+ end
+
+ it 'does not create a reference for an external user for an internal snippet' do
+ expect(visible_references(:internal, external_user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for a private snippet' do
+ expect(visible_references(:private, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for a private snippet' do
+ expect(visible_references(:private, user)).to be_empty
+ end
+ end
+
+ context 'when a project is internal and the snippets feature is enabled for project team members' do
+ before do
+ project.update_attribute(:visibility, Gitlab::VisibilityLevel::INTERNAL)
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE)
+ end
+
+ it 'creates a reference for a project member for a public snippet' do
+ expect(visible_references(:public, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for guest for a public snippet' do
+ expect(visible_references(:public, nil)).to be_empty
+ end
+
+ it 'does not create reference for a regular user for a public snippet' do
+ expect(visible_references(:public, user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for an internal snippet' do
+ expect(visible_references(:internal, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for an internal snippet' do
+ expect(visible_references(:internal, user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for a private snippet' do
+ expect(visible_references(:private, project_member)).to eq([link])
+ end
+
+ it 'does not create reference for a regular user for a private snippet' do
+ expect(visible_references(:private, user)).to be_empty
+ end
+ end
+
+ context 'when a project is private and the snippets feature is enabled for project team members' do
+ before do
+ project.update_attribute(:visibility, Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::PRIVATE)
+ end
+
+ it 'creates a reference for a project member for a public snippet' do
+ expect(visible_references(:public, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for guest for a public snippet' do
+ expect(visible_references(:public, nil)).to be_empty
+ end
+
+ it 'does not create a reference for a regular user for a public snippet' do
+ expect(visible_references(:public, user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for an internal snippet' do
+ expect(visible_references(:internal, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for an internal snippet' do
+ expect(visible_references(:internal, user)).to be_empty
+ end
+
+ it 'creates a reference for a project member for a private snippet' do
+ expect(visible_references(:private, project_member)).to eq([link])
+ end
+
+ it 'does not create a reference for a regular user for a private snippet' do
+ expect(visible_references(:private, user)).to be_empty
+ end
end
end
describe '#referenced_by' do
+ let(:snippet) { create(:snippet, project: project) }
describe 'when the link has a data-snippet attribute' do
context 'using an existing snippet ID' do
it 'returns an Array of snippets' do
@@ -31,7 +210,7 @@ describe Banzai::ReferenceParser::SnippetParser, lib: true do
it 'returns an empty Array' do
link['data-snippet'] = ''
- expect(subject.referenced_by([link])).to eq([])
+ expect(subject.referenced_by([link])).to be_empty
end
end
end
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index 592ed0d2b98..4d560667342 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -43,18 +43,9 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
expect(subject.referenced_by([link])).to eq([user])
end
- context 'when RequestStore is active' do
+ context 'when RequestStore is active', :request_store do
let(:other_user) { create(:user) }
- before do
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
- end
-
it 'does not return users from the first call in the second' do
link['data-user'] = user.id.to_s
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index fe2c00bb2ca..af0e7855a9b 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
module Ci
- describe GitlabCiYamlProcessor, lib: true do
+ describe GitlabCiYamlProcessor, :lib do
+ subject { described_class.new(config, path) }
let(:path) { 'path' }
describe 'our current .gitlab-ci.yml' do
@@ -82,6 +83,67 @@ module Ci
end
end
+ describe '#stage_seeds' do
+ context 'when no refs policy is specified' do
+ let(:config) do
+ YAML.dump(production: { stage: 'deploy', script: 'cap prod' },
+ rspec: { stage: 'test', script: 'rspec' },
+ spinach: { stage: 'test', script: 'spinach' })
+ end
+
+ let(:pipeline) { create(:ci_empty_pipeline) }
+
+ it 'correctly fabricates a stage seeds object' do
+ seeds = subject.stage_seeds(pipeline)
+
+ expect(seeds.size).to eq 2
+ expect(seeds.first.stage[:name]).to eq 'test'
+ expect(seeds.second.stage[:name]).to eq 'deploy'
+ expect(seeds.first.builds.dig(0, :name)).to eq 'rspec'
+ expect(seeds.first.builds.dig(1, :name)).to eq 'spinach'
+ expect(seeds.second.builds.dig(0, :name)).to eq 'production'
+ end
+ end
+
+ context 'when refs policy is specified' do
+ let(:config) do
+ YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
+ spinach: { stage: 'test', script: 'spinach', only: ['tags'] })
+ end
+
+ let(:pipeline) do
+ create(:ci_empty_pipeline, ref: 'feature', tag: true)
+ end
+
+ it 'returns stage seeds only assigned to master to master' do
+ seeds = subject.stage_seeds(pipeline)
+
+ expect(seeds.size).to eq 1
+ expect(seeds.first.stage[:name]).to eq 'test'
+ expect(seeds.first.builds.dig(0, :name)).to eq 'spinach'
+ end
+ end
+
+ context 'when source policy is specified' do
+ let(:config) do
+ YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
+ spinach: { stage: 'test', script: 'spinach', only: ['schedules'] })
+ end
+
+ let(:pipeline) do
+ create(:ci_empty_pipeline, source: :schedule)
+ end
+
+ it 'returns stage seeds only assigned to schedules' do
+ seeds = subject.stage_seeds(pipeline)
+
+ expect(seeds.size).to eq 1
+ expect(seeds.first.stage[:name]).to eq 'test'
+ expect(seeds.first.builds.dig(0, :name)).to eq 'spinach'
+ end
+ end
+ end
+
describe "#builds_for_ref" do
let(:type) { 'test' }
@@ -176,26 +238,44 @@ module Ci
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
end
- it "returns builds if only has a triggers keyword specified and a trigger is provided" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", type: type, only: ["triggers"] }
- })
+ it "returns builds if only has special keywords specified and source matches" do
+ possibilities = [{ keyword: 'pushes', source: 'push' },
+ { keyword: 'web', source: 'web' },
+ { keyword: 'triggers', source: 'trigger' },
+ { keyword: 'schedules', source: 'schedule' },
+ { keyword: 'api', source: 'api' },
+ { keyword: 'external', source: 'external' }]
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ possibilities.each do |possibility|
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
+ })
- expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(1)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1)
+ end
end
- it "does not return builds if only has a triggers keyword specified and no trigger is provided" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", type: type, only: ["triggers"] }
- })
+ it "does not return builds if only has special keywords specified and source doesn't match" do
+ possibilities = [{ keyword: 'pushes', source: 'web' },
+ { keyword: 'web', source: 'push' },
+ { keyword: 'triggers', source: 'schedule' },
+ { keyword: 'schedules', source: 'external' },
+ { keyword: 'api', source: 'trigger' },
+ { keyword: 'external', source: 'api' }]
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ possibilities.each do |possibility|
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
+ })
- expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0)
+ end
end
it "returns builds if only has current repository path" do
@@ -332,26 +412,44 @@ module Ci
expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
end
- it "does not return builds if except has a triggers keyword specified and a trigger is provided" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", type: type, except: ["triggers"] }
- })
+ it "does not return builds if except has special keywords specified and source matches" do
+ possibilities = [{ keyword: 'pushes', source: 'push' },
+ { keyword: 'web', source: 'web' },
+ { keyword: 'triggers', source: 'trigger' },
+ { keyword: 'schedules', source: 'schedule' },
+ { keyword: 'api', source: 'api' },
+ { keyword: 'external', source: 'external' }]
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ possibilities.each do |possibility|
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(0)
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(0)
+ end
end
- it "returns builds if except has a triggers keyword specified and no trigger is provided" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", type: type, except: ["triggers"] }
- })
+ it "returns builds if except has special keywords specified and source doesn't match" do
+ possibilities = [{ keyword: 'pushes', source: 'web' },
+ { keyword: 'web', source: 'push' },
+ { keyword: 'triggers', source: 'schedule' },
+ { keyword: 'schedules', source: 'external' },
+ { keyword: 'api', source: 'trigger' },
+ { keyword: 'external', source: 'api' }]
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ possibilities.each do |possibility|
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
+ })
- expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, possibility[:source]).size).to eq(1)
+ end
end
it "does not return builds if except has current repository path" do
@@ -498,62 +596,117 @@ module Ci
end
describe "Image and service handling" do
- it "returns image and service when defined" do
- config = YAML.dump({
- image: "ruby:2.1",
- services: ["mysql"],
- before_script: ["pwd"],
- rspec: { script: "rspec" }
- })
+ 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" }],
+ before_script: ["pwd"],
+ rspec: { script: "rspec" } })
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
- expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
- stage: "test",
- stage_idx: 1,
- name: "rspec",
- commands: "pwd\nrspec",
- coverage_regex: nil,
- tag_list: [],
- options: {
- image: "ruby:2.1",
- services: ["mysql"]
- },
- allow_failure: false,
- when: "on_success",
- environment: nil,
- yaml_variables: []
- })
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.1" },
+ services: [{ name: "mysql" }, { name: "docker:dind", alias: "docker" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
+
+ it "returns image and service when overridden for job" do
+ 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" } })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.5" },
+ services: [{ name: "postgresql", alias: "db-pg" }, { name: "docker:dind" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
end
- it "returns image and service when overridden for job" do
- config = YAML.dump({
- image: "ruby:2.1",
- services: ["mysql"],
- before_script: ["pwd"],
- rspec: { image: "ruby:2.5", services: ["postgresql"], script: "rspec" }
- })
+ context "when etended docker configuration is not used" do
+ it "returns image and service when defined" do
+ config = YAML.dump({ image: "ruby:2.1",
+ services: ["mysql", "docker:dind"],
+ before_script: ["pwd"],
+ rspec: { script: "rspec" } })
- config_processor = GitlabCiYamlProcessor.new(config, path)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
- expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
- stage: "test",
- stage_idx: 1,
- name: "rspec",
- commands: "pwd\nrspec",
- coverage_regex: nil,
- tag_list: [],
- options: {
- image: "ruby:2.5",
- services: ["postgresql"]
- },
- allow_failure: false,
- when: "on_success",
- environment: nil,
- yaml_variables: []
- })
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.1" },
+ services: [{ name: "mysql" }, { name: "docker:dind" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
+
+ it "returns image and service when overridden for job" do
+ config = YAML.dump({ image: "ruby:2.1",
+ services: ["mysql"],
+ before_script: ["pwd"],
+ rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
+ stage: "test",
+ stage_idx: 1,
+ name: "rspec",
+ commands: "pwd\nrspec",
+ coverage_regex: nil,
+ tag_list: [],
+ options: {
+ image: { name: "ruby:2.5" },
+ services: [{ name: "postgresql" }, { name: "docker:dind" }]
+ },
+ allow_failure: false,
+ when: "on_success",
+ environment: nil,
+ yaml_variables: []
+ })
+ end
end
end
@@ -786,8 +939,8 @@ module Ci
coverage_regex: nil,
tag_list: [],
options: {
- image: "ruby:2.1",
- services: ["mysql"],
+ image: { name: "ruby:2.1" },
+ services: [{ name: "mysql" }],
artifacts: {
name: "custom_name",
paths: ["logs/", "binaries/"],
@@ -1163,7 +1316,7 @@ EOT
config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image config should be a string")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image config should be a hash or a string")
end
it "returns errors if job name is blank" do
@@ -1184,35 +1337,35 @@ EOT
config = YAML.dump({ rspec: { script: "test", image: ["test"] } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:image config should be a string")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:image config should be a hash or a string")
end
it "returns errors if services parameter is not an array" do
config = YAML.dump({ services: "test", rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be a array")
end
it "returns errors if services parameter is not an array of strings" do
config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "service config should be a hash or a string")
end
it "returns errors if job services parameter is not an array" do
config = YAML.dump({ rspec: { script: "test", services: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:services config should be a array")
end
it "returns errors if job services parameter is not an array of strings" do
config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "service config should be a hash or a string")
end
it "returns error if job configuration is invalid" do
@@ -1226,7 +1379,7 @@ EOT
config = YAML.dump({ extra: { script: 'rspec', services: "test" } })
expect do
GitlabCiYamlProcessor.new(config, path)
- end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:extra:services config should be an array of strings")
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:extra:services config should be a array")
end
it "returns errors if there are no jobs defined" do
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 33ab005667a..2b26a318583 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -77,7 +77,10 @@ describe ExtractsPath, lib: true do
context 'without a path' do
let(:params) { { ref: 'v1.0.0.atom' } }
- before { assign_ref_vars }
+
+ before do
+ assign_ref_vars
+ end
it 'sets the un-suffixed version as @ref' do
expect(@ref).to eq('v1.0.0')
diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
index 94dcddcc30c..fc72df575be 100644
--- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
+++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
@@ -40,7 +40,9 @@ describe Gitlab::Auth::UniqueIpsLimiter, :redis, lib: true do
end
context 'allow 2 unique ips' do
- before { current_application_settings.update!(unique_ips_limit_per_user: 2) }
+ before do
+ current_application_settings.update!(unique_ips_limit_per_user: 2)
+ end
it 'blocks user trying to login from third ip' do
change_ip('ip1')
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 50bc3ef1b7c..d09da951869 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -17,7 +17,11 @@ describe Gitlab::Auth, lib: true do
end
it 'OPTIONAL_SCOPES contains all non-default scopes' do
- expect(subject::OPTIONAL_SCOPES).to eq [:read_user, :openid]
+ expect(subject::OPTIONAL_SCOPES).to eq %i[read_user read_registry openid]
+ end
+
+ it 'REGISTRY_SCOPES contains all registry related scopes' do
+ expect(subject::REGISTRY_SCOPES).to eq %i[read_registry]
end
end
@@ -143,6 +147,13 @@ describe Gitlab::Auth, lib: true do
expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, full_authentication_abilities))
end
+ it 'succeeds for personal access tokens with the `read_registry` scope' do
+ personal_access_token = create(:personal_access_token, scopes: ['read_registry'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, [:read_container_image]))
+ end
+
it 'succeeds if it is an impersonation token' do
impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api'])
@@ -150,18 +161,11 @@ describe Gitlab::Auth, lib: true do
expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(impersonation_token.user, nil, :personal_token, full_authentication_abilities))
end
- it 'fails for personal access tokens with other scopes' do
+ it 'limits abilities based on scope' do
personal_access_token = create(:personal_access_token, scopes: ['read_user'])
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
- expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
- end
-
- it 'fails for impersonation token with other scopes' do
- impersonation_token = create(:personal_access_token, scopes: ['read_user'])
-
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
- expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, []))
end
it 'fails if password is nil' do
@@ -200,6 +204,12 @@ describe Gitlab::Auth, lib: true do
expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
expect(gl_auth.find_for_git_client(login, 'bar', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new)
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 }
+
+ expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalTokenError)
+ end
end
describe 'find_with_user_password' do
diff --git a/spec/lib/gitlab/background_migration_spec.rb b/spec/lib/gitlab/background_migration_spec.rb
new file mode 100644
index 00000000000..f2073b9bcb3
--- /dev/null
+++ b/spec/lib/gitlab/background_migration_spec.rb
@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration do
+ describe '.steal' do
+ it 'steals jobs from a queue' do
+ queue = [double(:job, args: ['Foo', [10, 20]])]
+
+ allow(Sidekiq::Queue).to receive(:new).
+ with(BackgroundMigrationWorker.sidekiq_options['queue']).
+ and_return(queue)
+
+ expect(queue[0]).to receive(:delete)
+
+ expect(described_class).to receive(:perform).with('Foo', [10, 20])
+
+ described_class.steal('Foo')
+ end
+
+ it 'does not steal jobs for a different migration' do
+ queue = [double(:job, args: ['Foo', [10, 20]])]
+
+ allow(Sidekiq::Queue).to receive(:new).
+ with(BackgroundMigrationWorker.sidekiq_options['queue']).
+ and_return(queue)
+
+ expect(described_class).not_to receive(:perform)
+
+ expect(queue[0]).not_to receive(:delete)
+
+ described_class.steal('Bar')
+ end
+ end
+
+ describe '.perform' do
+ it 'performs a background migration' do
+ instance = double(:instance)
+ klass = double(:klass, new: instance)
+
+ expect(described_class).to receive(:const_get).
+ with('Foo').
+ and_return(klass)
+
+ expect(instance).to receive(:perform).with(10, 20)
+
+ described_class.perform('Foo', [10, 20])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb
new file mode 100644
index 00000000000..51c1e9d657b
--- /dev/null
+++ b/spec/lib/gitlab/backup/repository_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+describe Backup::Repository, lib: true do
+ let(:progress) { StringIO.new }
+ let!(:project) { create(:empty_project) }
+
+ before do
+ allow(progress).to receive(:puts)
+ allow(progress).to receive(:print)
+
+ allow_any_instance_of(String).to receive(:color) do |string, _color|
+ string
+ end
+
+ allow_any_instance_of(described_class).to receive(:progress).and_return(progress)
+ end
+
+ describe '#dump' do
+ describe 'repo failure' do
+ before do
+ allow_any_instance_of(Repository).to receive(:empty_repo?).and_raise(Rugged::OdbError)
+ allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0])
+ end
+
+ it 'does not raise error' do
+ expect { described_class.new.dump }.not_to raise_error
+ end
+
+ it 'shows the appropriate error' do
+ described_class.new.dump
+
+ expect(progress).to have_received(:puts).with("Ignoring repository error and continuing backing up project: #{project.full_path} - Rugged::OdbError")
+ end
+ end
+
+ describe 'command failure' do
+ before do
+ allow_any_instance_of(Repository).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
+ end
+
+ it 'shows the appropriate error' do
+ described_class.new.dump
+
+ expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error")
+ end
+ end
+ end
+
+ describe '#restore' do
+ describe 'command failure' do
+ before do
+ allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
+ end
+
+ it 'shows the appropriate error' do
+ described_class.new.restore
+
+ expect(progress).to have_received(:puts).with("Ignoring error on #{project.full_path} - error")
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/badge/build/status_spec.rb b/spec/lib/gitlab/badge/build/status_spec.rb
index 3c5414701a7..6abf4ca46a9 100644
--- a/spec/lib/gitlab/badge/build/status_spec.rb
+++ b/spec/lib/gitlab/badge/build/status_spec.rb
@@ -29,7 +29,9 @@ describe Gitlab::Badge::Build::Status do
let!(:build) { create_build(project, sha, branch) }
context 'build success' do
- before { build.success! }
+ before do
+ build.success!
+ end
describe '#status' do
it 'is successful' do
@@ -39,7 +41,9 @@ describe Gitlab::Badge::Build::Status do
end
context 'build failed' do
- before { build.drop! }
+ before do
+ build.drop!
+ end
describe '#status' do
it 'failed' do
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb
index ec6d3e34a96..3799a324db4 100644
--- a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb
+++ b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::ChatCommands::Presenters::IssueSearch do
let(:project) { create(:empty_project) }
let(:message) { subject[:text] }
- before { create_list(:issue, 2, project: project) }
+ before do
+ create_list(:issue, 2, project: project)
+ end
subject { described_class.new(project.issues).present }
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index c0c309d8179..643e590438a 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -20,7 +20,9 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
).exec
end
- before { project.add_developer(user) }
+ before do
+ project.add_developer(user)
+ end
context 'without failed checks' do
it "doesn't raise an error" do
@@ -50,7 +52,9 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
let!(:protected_tag) { create(:protected_tag, project: project, name: 'v*') }
context 'as master' do
- before { project.add_master(user) }
+ before do
+ project.add_master(user)
+ end
context 'deletion' do
let(:oldrev) { 'be93687618e4b132087f430a4d8fc3a609c9b77c' }
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
index 382385dfd6b..773a52cdfbc 100644
--- a/spec/lib/gitlab/ci/build/image_spec.rb
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -10,12 +10,28 @@ describe Gitlab::Ci::Build::Image do
let(:image_name) { 'ruby:2.1' }
let(:job) { create(:ci_build, options: { image: image_name } ) }
- it 'fabricates an object of the proper class' do
- is_expected.to be_kind_of(described_class)
+ context 'when image is defined as string' do
+ it 'fabricates an object of the proper class' do
+ is_expected.to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated object with the proper name attribute' do
+ expect(subject.name).to eq(image_name)
+ end
end
- it 'populates fabricated object with the proper name attribute' do
- expect(subject.name).to eq(image_name)
+ context 'when image is defined as hash' do
+ let(:entrypoint) { '/bin/sh' }
+ let(:job) { create(:ci_build, options: { image: { name: image_name, entrypoint: entrypoint } } ) }
+
+ it 'fabricates an object of the proper class' do
+ is_expected.to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated object with the proper attributes' do
+ expect(subject.name).to eq(image_name)
+ expect(subject.entrypoint).to eq(entrypoint)
+ end
end
context 'when image name is empty' do
@@ -41,10 +57,39 @@ describe Gitlab::Ci::Build::Image do
let(:service_image_name) { 'postgres' }
let(:job) { create(:ci_build, options: { services: [service_image_name] }) }
- it 'fabricates an non-empty array of objects' do
- is_expected.to be_kind_of(Array)
- is_expected.not_to be_empty
- expect(subject.first.name).to eq(service_image_name)
+ context 'when service is defined as string' do
+ it 'fabricates an non-empty array of objects' do
+ is_expected.to be_kind_of(Array)
+ is_expected.not_to be_empty
+ end
+
+ it 'populates fabricated objects with the proper name attributes' do
+ expect(subject.first).to be_kind_of(described_class)
+ expect(subject.first.name).to eq(service_image_name)
+ end
+ end
+
+ context 'when service is defined as hash' do
+ let(:service_entrypoint) { '/bin/sh' }
+ let(:service_alias) { 'db' }
+ let(:service_command) { 'sleep 30' }
+ let(:job) do
+ create(:ci_build, options: { services: [{ name: service_image_name, entrypoint: service_entrypoint,
+ alias: service_alias, command: service_command }] })
+ end
+
+ it 'fabricates an non-empty array of objects' do
+ is_expected.to be_kind_of(Array)
+ is_expected.not_to be_empty
+ expect(subject.first).to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated objects with the proper attributes' do
+ expect(subject.first.name).to eq(service_image_name)
+ expect(subject.first.entrypoint).to eq(service_entrypoint)
+ expect(subject.first.alias).to eq(service_alias)
+ expect(subject.first.command).to eq(service_command)
+ end
end
context 'when service image name 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 2ed120f356a..878b1d6b862 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::Ci::Config::Entry::Cache do
let(:entry) { described_class.new(config) }
describe 'validations' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry config value is correct' do
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
index c330e609337..3c0007f4d57 100644
--- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
@@ -3,7 +3,9 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Environment do
let(:entry) { described_class.new(config) }
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when configuration is a string' do
let(:config) { 'production' }
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index 23270ad5053..293f112b2b0 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -33,7 +33,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
describe '#compose!' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
it 'creates nodes hash' do
expect(global.descendants).to be_an Array
@@ -79,7 +81,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
context 'when composed' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
describe '#errors' do
it 'has no errors' do
@@ -95,13 +99,13 @@ describe Gitlab::Ci::Config::Entry::Global do
describe '#image_value' do
it 'returns valid image' do
- expect(global.image_value).to eq 'ruby:2.2'
+ expect(global.image_value).to eq(name: 'ruby:2.2')
end
end
describe '#services_value' do
it 'returns array of services' do
- expect(global.services_value).to eq ['postgres:9.1', 'mysql:5.5']
+ expect(global.services_value).to eq [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }]
end
end
@@ -150,8 +154,8 @@ describe Gitlab::Ci::Config::Entry::Global do
script: %w[rspec ls],
before_script: %w(ls pwd),
commands: "ls\npwd\nrspec\nls",
- image: 'ruby:2.2',
- services: ['postgres:9.1', 'mysql:5.5'],
+ image: { name: 'ruby:2.2' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'] },
variables: { 'VAR' => 'value' },
@@ -161,8 +165,8 @@ describe Gitlab::Ci::Config::Entry::Global do
before_script: [],
script: %w[spinach],
commands: 'spinach',
- image: 'ruby:2.2',
- services: ['postgres:9.1', 'mysql:5.5'],
+ image: { name: 'ruby:2.2' },
+ services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'] },
variables: {},
@@ -175,7 +179,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
context 'when most of entires not defined' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
let(:hash) do
{ cache: { key: 'a' }, rspec: { script: %w[ls] } }
@@ -218,7 +224,9 @@ describe Gitlab::Ci::Config::Entry::Global do
# details.
#
context 'when entires specified but not defined' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
let(:hash) do
{ variables: nil, rspec: { script: 'rspec' } }
@@ -233,7 +241,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
context 'when configuration is not valid' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
context 'when before script is not an array' do
let(:hash) do
@@ -297,7 +307,9 @@ describe Gitlab::Ci::Config::Entry::Global do
end
describe '#[]' do
- before { global.compose! }
+ before do
+ global.compose!
+ end
let(:hash) do
{ cache: { key: 'a' }, rspec: { script: 'ls' } }
diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb
index 3c99cb0a1ee..bca22e39500 100644
--- a/spec/lib/gitlab/ci/config/entry/image_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb
@@ -3,43 +3,104 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Image do
let(:entry) { described_class.new(config) }
- describe 'validation' do
- context 'when entry config value is correct' do
- let(:config) { 'ruby:2.2' }
+ context 'when configuration is a string' do
+ let(:config) { 'ruby:2.2' }
- describe '#value' do
- it 'returns image string' do
- expect(entry.value).to eq 'ruby:2.2'
- end
+ describe '#value' do
+ it 'returns image hash' do
+ expect(entry.value).to eq({ name: 'ruby:2.2' })
end
+ end
+
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(entry.errors).to be_empty
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#image' do
+ it "returns image's name" do
+ expect(entry.name).to eq 'ruby:2.2'
+ end
+ end
- describe '#errors' do
- it 'does not append errors' do
- expect(entry.errors).to be_empty
- end
+ describe '#entrypoint' do
+ it "returns image's entrypoint" do
+ expect(entry.entrypoint).to be_nil
end
+ end
+ end
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
+ context 'when configuration is a hash' do
+ let(:config) { { name: 'ruby:2.2', entrypoint: '/bin/sh' } }
+
+ describe '#value' do
+ it 'returns image hash' do
+ expect(entry.value).to eq(config)
end
end
- context 'when entry value is not correct' do
- let(:config) { ['ruby:2.2'] }
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(entry.errors).to be_empty
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors)
- .to include 'image config should be a string'
- end
+ describe '#image' do
+ it "returns image's name" do
+ expect(entry.name).to eq 'ruby:2.2'
end
+ end
+
+ describe '#entrypoint' do
+ it "returns image's entrypoint" do
+ expect(entry.entrypoint).to eq '/bin/sh'
+ end
+ end
+ end
+
+ context 'when entry value is not correct' do
+ let(:config) { ['ruby:2.2'] }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'image config should be a hash or a string'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
+
+ context 'when unexpected key is specified' do
+ let(:config) { { name: 'ruby:2.2', non_existing: 'test' } }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'image config contains unknown keys: non_existing'
+ end
+ end
- describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
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 9249bb9c172..92cba689f47 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -18,7 +18,9 @@ describe Gitlab::Ci::Config::Entry::Job do
end
describe 'validations' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry config value is correct' do
let(:config) { { script: 'rspec' } }
@@ -97,14 +99,16 @@ describe Gitlab::Ci::Config::Entry::Job do
let(:deps) { double('deps', '[]' => unspecified) }
context 'when job config overrides global config' do
- before { entry.compose!(deps) }
+ before do
+ entry.compose!(deps)
+ end
let(:config) do
{ script: 'rspec', image: 'some_image', cache: { key: 'test' } }
end
it 'overrides global config' do
- expect(entry[:image].value).to eq 'some_image'
+ expect(entry[:image].value).to eq(name: 'some_image')
expect(entry[:cache].value).to eq(key: 'test')
end
end
@@ -125,10 +129,14 @@ describe Gitlab::Ci::Config::Entry::Job do
end
context 'when composed' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
describe '#value' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry is correct' do
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index 7d104372ac6..c0a2b6517e3 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::Ci::Config::Entry::Jobs do
let(:entry) { described_class.new(config) }
describe 'validations' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
context 'when entry config value is correct' do
let(:config) { { rspec: { script: 'rspec' } } }
@@ -48,7 +50,9 @@ describe Gitlab::Ci::Config::Entry::Jobs do
end
context 'when valid job entries composed' do
- before { entry.compose! }
+ before do
+ entry.compose!
+ end
let(:config) do
{ rspec: { script: 'rspec' },
diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb
new file mode 100644
index 00000000000..7202fe525e4
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb
@@ -0,0 +1,119 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::Entry::Service do
+ let(:entry) { described_class.new(config) }
+
+ before do
+ entry.compose!
+ end
+
+ context 'when configuration is a string' do
+ let(:config) { 'postgresql:9.5' }
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#value' do
+ it 'returns valid hash' do
+ expect(entry.value).to include(name: 'postgresql:9.5')
+ end
+ end
+
+ describe '#image' do
+ it "returns service's image name" do
+ expect(entry.name).to eq 'postgresql:9.5'
+ end
+ end
+
+ describe '#alias' do
+ it "returns service's alias" do
+ expect(entry.alias).to be_nil
+ end
+ end
+
+ describe '#command' do
+ it "returns service's command" do
+ expect(entry.command).to be_nil
+ end
+ end
+ end
+
+ context 'when configuration is a hash' do
+ let(:config) do
+ { name: 'postgresql:9.5', alias: 'db', command: 'cmd', entrypoint: '/bin/sh' }
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#value' do
+ it 'returns valid hash' do
+ expect(entry.value).to eq config
+ end
+ end
+
+ describe '#image' do
+ it "returns service's image name" do
+ expect(entry.name).to eq 'postgresql:9.5'
+ end
+ end
+
+ describe '#alias' do
+ it "returns service's alias" do
+ expect(entry.alias).to eq 'db'
+ end
+ end
+
+ describe '#command' do
+ it "returns service's command" do
+ expect(entry.command).to eq 'cmd'
+ end
+ end
+
+ describe '#entrypoint' do
+ it "returns service's entrypoint" do
+ expect(entry.entrypoint).to eq '/bin/sh'
+ end
+ end
+ end
+
+ context 'when entry value is not correct' do
+ let(:config) { ['postgresql:9.5'] }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'service config should be a hash or a string'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
+
+ context 'when unexpected key is specified' do
+ let(:config) { { name: 'postgresql:9.5', non_existing: 'test' } }
+
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors)
+ .to include 'service config contains unknown keys: non_existing'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/services_spec.rb b/spec/lib/gitlab/ci/config/entry/services_spec.rb
index 66fad3b6b16..7c4319aee63 100644
--- a/spec/lib/gitlab/ci/config/entry/services_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/services_spec.rb
@@ -3,37 +3,32 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Services do
let(:entry) { described_class.new(config) }
- describe 'validations' do
- context 'when entry config value is correct' do
- let(:config) { ['postgres:9.1', 'mysql:5.5'] }
+ before do
+ entry.compose!
+ end
- describe '#value' do
- it 'returns array of services as is' do
- expect(entry.value).to eq config
- end
- end
+ context 'when configuration is valid' do
+ let(:config) { ['postgresql:9.5', { name: 'postgresql:9.1', alias: 'postgres_old' }] }
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
end
end
- context 'when entry value is not correct' do
- let(:config) { 'ls' }
-
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors)
- .to include 'services config should be an array of strings'
- end
+ describe '#value' do
+ it 'returns valid array' do
+ expect(entry.value).to eq([{ name: 'postgresql:9.5' }, { name: 'postgresql:9.1', alias: 'postgres_old' }])
end
+ end
+ end
+
+ context 'when configuration is invalid' do
+ let(:config) { 'postgresql:9.5' }
- describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
+ describe '#valid?' do
+ it 'is invalid' do
+ expect(entry).not_to be_valid
end
end
end
diff --git a/spec/lib/gitlab/ci/stage/seed_spec.rb b/spec/lib/gitlab/ci/stage/seed_spec.rb
new file mode 100644
index 00000000000..d7e91a5a62c
--- /dev/null
+++ b/spec/lib/gitlab/ci/stage/seed_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Stage::Seed do
+ let(:pipeline) { create(:ci_empty_pipeline) }
+
+ let(:builds) do
+ [{ name: 'rspec' }, { name: 'spinach' }]
+ end
+
+ subject do
+ described_class.new(pipeline, 'test', builds)
+ end
+
+ describe '#stage' do
+ it 'returns hash attributes of a stage' do
+ expect(subject.stage).to be_a Hash
+ expect(subject.stage).to include(:name, :project)
+ end
+ end
+
+ describe '#builds' do
+ it 'returns hash attributes of all builds' do
+ expect(subject.builds.size).to eq 2
+ expect(subject.builds).to all(include(ref: 'master'))
+ expect(subject.builds).to all(include(tag: false))
+ expect(subject.builds).to all(include(project: pipeline.project))
+ expect(subject.builds)
+ .to all(include(trigger_request: pipeline.trigger_requests.first))
+ end
+ end
+
+ describe '#user=' do
+ let(:user) { build(:user) }
+
+ it 'assignes relevant pipeline attributes' do
+ subject.user = user
+
+ expect(subject.builds).to all(include(user: user))
+ end
+ end
+
+ describe '#create!' do
+ it 'creates all stages and builds' do
+ subject.create!
+
+ expect(pipeline.reload.stages.count).to eq 1
+ expect(pipeline.reload.builds.count).to eq 2
+ expect(pipeline.builds).to all(satisfy { |job| job.stage_id.present? })
+ expect(pipeline.builds).to all(satisfy { |job| job.pipeline.present? })
+ expect(pipeline.builds).to all(satisfy { |job| job.project.present? })
+ expect(pipeline.stages)
+ .to all(satisfy { |stage| stage.pipeline.present? })
+ expect(pipeline.stages)
+ .to all(satisfy { |stage| stage.project.present? })
+ 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 8ad9b7cdf07..114d2490490 100644
--- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -47,7 +47,9 @@ describe Gitlab::Ci::Status::Build::Cancelable do
describe '#has_action?' do
context 'when user is allowed to update build' do
- before { build.project.team << [user, :developer] }
+ before do
+ build.project.team << [user, :developer]
+ end
it { is_expected.to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
index 72bd7c4eb93..03d1f46b517 100644
--- a/spec/lib/gitlab/ci/status/build/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -17,13 +17,17 @@ describe Gitlab::Ci::Status::Build::Common do
describe '#has_details?' do
context 'when user has access to read build' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it { is_expected.to have_details }
end
context 'when user does not have access to read build' do
- before { project.update(public_builds: false) }
+ before do
+ project.update(public_builds: false)
+ end
it { is_expected.not_to have_details }
end
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index 3f30b2c38f2..c8a97016f20 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Ci::Status::Build::Factory do
let(:status) { factory.fabricate! }
let(:factory) { described_class.new(build, user) }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
context 'when build is successful' do
let(:build) { create(:ci_build, :success) }
diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb
index 0e15a5f3c6b..32b2e62e4e0 100644
--- a/spec/lib/gitlab/ci/status/build/play_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -28,7 +28,9 @@ describe Gitlab::Ci::Status::Build::Play do
end
context 'when user can not push to the branch' do
- before { build.project.add_developer(user) }
+ before do
+ build.project.add_developer(user)
+ end
it { is_expected.not_to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
index 2db0f8d29bd..099d873fc01 100644
--- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -47,7 +47,9 @@ describe Gitlab::Ci::Status::Build::Retryable do
describe '#has_action?' do
context 'when user is allowed to update build' do
- before { build.project.team << [user, :developer] }
+ before do
+ build.project.team << [user, :developer]
+ end
it { is_expected.to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
index 8d021c35a69..23902f26b1a 100644
--- a/spec/lib/gitlab/ci/status/build/stop_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -19,7 +19,9 @@ describe Gitlab::Ci::Status::Build::Stop do
describe '#has_action?' do
context 'when user is allowed to update build' do
- before { build.project.team << [user, :developer] }
+ before do
+ build.project.team << [user, :developer]
+ end
it { is_expected.to have_action }
end
diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb
index 5a97d98b55f..b38fbee2486 100644
--- a/spec/lib/gitlab/ci/status/external/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/external/common_spec.rb
@@ -4,9 +4,10 @@ describe Gitlab::Ci::Status::External::Common do
let(:user) { create(:user) }
let(:project) { external_status.project }
let(:external_target_url) { 'http://example.gitlab.com/status' }
+ let(:external_description) { 'my description' }
let(:external_status) do
- create(:generic_commit_status, target_url: external_target_url)
+ create(:generic_commit_status, target_url: external_target_url, description: external_description)
end
subject do
@@ -15,13 +16,21 @@ describe Gitlab::Ci::Status::External::Common do
.extend(described_class)
end
+ describe '#label' do
+ it 'returns description' do
+ expect(subject.label).to eq external_description
+ end
+ end
+
describe '#has_action?' do
it { is_expected.not_to have_action }
end
describe '#has_details?' do
context 'when user has access to read commit status' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it { is_expected.to have_details }
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
index d665674bf70..f5fd31e8d03 100644
--- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
@@ -17,7 +17,9 @@ describe Gitlab::Ci::Status::Pipeline::Common do
describe '#has_details?' do
context 'when user has access to read pipeline' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it { is_expected.to have_details }
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 3fdafd867da..30aa463faf8 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -7,7 +7,42 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
)
end
- before { allow(model).to receive(:puts) }
+ before do
+ allow(model).to receive(:puts)
+ end
+
+ describe '#add_timestamps_with_timezone' do
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ context 'using PostgreSQL' do
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(true)
+ allow(model).to receive(:disable_statement_timeout)
+ end
+
+ it 'adds "created_at" and "updated_at" fields with the "datetime_with_timezone" data type' do
+ expect(model).to receive(:add_column).with(:foo, :created_at, :datetime_with_timezone, { null: false })
+ expect(model).to receive(:add_column).with(:foo, :updated_at, :datetime_with_timezone, { null: false })
+
+ model.add_timestamps_with_timezone(:foo)
+ end
+ end
+
+ context 'using MySQL' do
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(false)
+ end
+
+ it 'adds "created_at" and "updated_at" fields with "datetime_with_timezone" data type' do
+ expect(model).to receive(:add_column).with(:foo, :created_at, :datetime_with_timezone, { null: false })
+ expect(model).to receive(:add_column).with(:foo, :updated_at, :datetime_with_timezone, { null: false })
+
+ model.add_timestamps_with_timezone(:foo)
+ end
+ end
+ end
describe '#add_concurrent_index' do
context 'outside a transaction' do
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 9b1d66a1b1c..26e5d73d333 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -53,14 +53,18 @@ describe Gitlab::Database, lib: true do
describe '.nulls_last_order' do
context 'when using PostgreSQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(true) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(true)
+ end
it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column ASC NULLS LAST'}
it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC NULLS LAST'}
end
context 'when using MySQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(false) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(false)
+ end
it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column IS NULL, column ASC'}
it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC'}
@@ -69,14 +73,18 @@ describe Gitlab::Database, lib: true do
describe '.nulls_first_order' do
context 'when using PostgreSQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(true) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(true)
+ end
it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC NULLS FIRST'}
it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column DESC NULLS FIRST'}
end
context 'when using MySQL' do
- before { expect(described_class).to receive(:postgresql?).and_return(false) }
+ before do
+ expect(described_class).to receive(:postgresql?).and_return(false)
+ end
it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC'}
it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column IS NULL, column DESC'}
diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb
new file mode 100644
index 00000000000..a8173558c00
--- /dev/null
+++ b/spec/lib/gitlab/diff/diff_refs_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe Gitlab::Diff::DiffRefs, lib: true do
+ let(:project) { create(:project, :repository) }
+
+ describe '#compare_in' do
+ context 'with diff refs for the initial commit' do
+ let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') }
+ subject { commit.diff_refs }
+
+ it 'returns an appropriate comparison' do
+ compare = subject.compare_in(project)
+
+ expect(compare.diff_refs).to eq(subject)
+ end
+ end
+
+ context 'with diff refs for a commit' do
+ let(:commit) { project.commit('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
+ subject { commit.diff_refs }
+
+ it 'returns an appropriate comparison' do
+ compare = subject.compare_in(project)
+
+ expect(compare.diff_refs).to eq(subject)
+ end
+ end
+
+ context 'with diff refs for a comparison through the base' do
+ subject do
+ described_class.new(
+ start_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', # feature
+ base_sha: 'ae73cb07c9eeaf35924a10f713b364d32b2dd34f',
+ head_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a' # master
+ )
+ end
+
+ it 'returns an appropriate comparison' do
+ compare = subject.compare_in(project)
+
+ expect(compare.diff_refs).to eq(subject)
+ end
+ end
+
+ context 'with diff refs for a straight comparison' do
+ subject do
+ described_class.new(
+ start_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', # feature
+ base_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9',
+ head_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a' # master
+ )
+ end
+
+ it 'returns an appropriate comparison' do
+ compare = subject.compare_in(project)
+
+ expect(compare.diff_refs).to eq(subject)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
index f2bc15d39d7..d81774c8b8f 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
@@ -5,15 +5,7 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
let(:diff_files) { described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files }
it 'does not highlight binary files' do
- allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => false))
-
- expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
-
- diff_files
- end
-
- it 'does not highlight file if blob is not accessable' do
- allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(false)
expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
@@ -21,7 +13,7 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
end
it 'does not files marked as undiffable in .gitattributes' do
- allow_any_instance_of(Repository).to receive(:diffable?).and_return(false)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(false)
expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 050689b7c9a..f289131cc3a 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Diff::File, lib: true do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.raw_diffs.first }
- let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
+ let(:diff_file) { described_class.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
describe '#diff_lines' do
let(:diff_lines) { diff_file.diff_lines }
@@ -63,11 +63,334 @@ describe Gitlab::Diff::File, lib: true do
end
end
- describe '#blob' do
+ describe '#new_blob' do
it 'returns blob of new commit' do
- data = diff_file.blob.data
+ data = diff_file.new_blob.data
expect(data).to include('raise RuntimeError, "System commands must be given as an array of strings"')
end
end
+
+ describe '#diffable?' do
+ let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') }
+ let(:diffs) { commit.diffs }
+
+ before do
+ info_dir_path = File.join(project.repository.path_to_repo, 'info')
+
+ FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path)
+ File.write(File.join(info_dir_path, 'attributes'), "*.md -diff\n")
+ end
+
+ it "returns true for files that do not have attributes" do
+ diff_file = diffs.diff_file_with_new_path('LICENSE')
+ expect(diff_file.diffable?).to be_truthy
+ end
+
+ it "returns false for files that have been marked as not being diffable in attributes" do
+ diff_file = diffs.diff_file_with_new_path('README.md')
+ expect(diff_file.diffable?).to be_falsey
+ end
+ end
+
+ describe '#content_changed?' do
+ context 'when created' do
+ let(:commit) { project.commit('33f3729a45c02fc67d00adb1b8bca394b0e761d9') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
+
+ it 'returns false' do
+ expect(diff_file.content_changed?).to be_falsey
+ end
+ end
+
+ context 'when deleted' do
+ let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') }
+ let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') }
+
+ it 'returns false' do
+ expect(diff_file.content_changed?).to be_falsey
+ end
+ end
+
+ context 'when renamed' do
+ let(:commit) { project.commit('6907208d755b60ebeacb2e9dfea74c92c3449a1f') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/js/commit.coffee') }
+
+ before do
+ allow(diff_file.new_blob).to receive(:id).and_return(diff_file.old_blob.id)
+ end
+
+ it 'returns false' do
+ expect(diff_file.content_changed?).to be_falsey
+ end
+ end
+
+ context 'when content changed' do
+ context 'when binary' do
+ let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
+
+ it 'returns true' do
+ expect(diff_file.content_changed?).to be_truthy
+ end
+ end
+
+ context 'when not binary' do
+ let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
+
+ it 'returns true' do
+ expect(diff_file.content_changed?).to be_truthy
+ end
+ end
+ end
+ end
+
+ describe '#simple_viewer' do
+ context 'when the file is not diffable' do
+ before do
+ allow(diff_file).to receive(:diffable?).and_return(false)
+ end
+
+ it 'returns a Not Diffable viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::NotDiffable)
+ end
+ end
+
+ context 'when the content changed' do
+ context 'when the file represented by the diff file is binary' do
+ before do
+ allow(diff_file).to receive(:raw_binary?).and_return(true)
+ end
+
+ it 'returns a No Preview viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::NoPreview)
+ end
+ end
+
+ context 'when the diff file old and new blob types are different' do
+ before do
+ allow(diff_file).to receive(:different_type?).and_return(true)
+ end
+
+ it 'returns a No Preview viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::NoPreview)
+ end
+ end
+
+ context 'when the file represented by the diff file is text-based' do
+ it 'returns a text viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Text)
+ end
+ end
+ end
+
+ context 'when created' do
+ let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
+
+ before do
+ allow(diff_file).to receive(:content_changed?).and_return(nil)
+ end
+
+ context 'when the file represented by the diff file is binary' do
+ before do
+ allow(diff_file).to receive(:raw_binary?).and_return(true)
+ end
+
+ it 'returns an Added viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Added)
+ end
+ end
+
+ context 'when the diff file old and new blob types are different' do
+ before do
+ allow(diff_file).to receive(:different_type?).and_return(true)
+ end
+
+ it 'returns an Added viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Added)
+ end
+ end
+
+ context 'when the file represented by the diff file is text-based' do
+ it 'returns a text viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Text)
+ end
+ end
+ end
+
+ context 'when deleted' do
+ let(:commit) { project.commit('d59c60028b053793cecfb4022de34602e1a9218e') }
+ let(:diff_file) { commit.diffs.diff_file_with_old_path('files/js/commit.js.coffee') }
+
+ before do
+ allow(diff_file).to receive(:content_changed?).and_return(nil)
+ end
+
+ context 'when the file represented by the diff file is binary' do
+ before do
+ allow(diff_file).to receive(:raw_binary?).and_return(true)
+ end
+
+ it 'returns a Deleted viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Deleted)
+ end
+ end
+
+ context 'when the diff file old and new blob types are different' do
+ before do
+ allow(diff_file).to receive(:different_type?).and_return(true)
+ end
+
+ it 'returns a Deleted viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Deleted)
+ end
+ end
+
+ context 'when the file represented by the diff file is text-based' do
+ it 'returns a text viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Text)
+ end
+ end
+ end
+
+ context 'when renamed' do
+ let(:commit) { project.commit('6907208d755b60ebeacb2e9dfea74c92c3449a1f') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/js/commit.coffee') }
+
+ before do
+ allow(diff_file).to receive(:content_changed?).and_return(nil)
+ end
+
+ it 'returns a Renamed viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::Renamed)
+ end
+ end
+
+ context 'when mode changed' do
+ before do
+ allow(diff_file).to receive(:content_changed?).and_return(nil)
+ allow(diff_file).to receive(:mode_changed?).and_return(true)
+ end
+
+ it 'returns a Mode Changed viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::ModeChanged)
+ end
+ end
+ end
+
+ describe '#rich_viewer' do
+ let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
+
+ context 'when the diff file has a matching viewer' do
+ context 'when the diff file content did not change' do
+ before do
+ allow(diff_file).to receive(:content_changed?).and_return(false)
+ end
+
+ it 'returns nil' do
+ expect(diff_file.rich_viewer).to be_nil
+ end
+ end
+
+ context 'when the diff file is not diffable' do
+ before do
+ allow(diff_file).to receive(:diffable?).and_return(false)
+ end
+
+ it 'returns nil' do
+ expect(diff_file.rich_viewer).to be_nil
+ end
+ end
+
+ context 'when the diff file old and new blob types are different' do
+ before do
+ allow(diff_file).to receive(:different_type?).and_return(true)
+ end
+
+ it 'returns nil' do
+ expect(diff_file.rich_viewer).to be_nil
+ end
+ end
+
+ context 'when the diff file has an external storage error' do
+ before do
+ allow(diff_file).to receive(:external_storage_error?).and_return(true)
+ end
+
+ it 'returns nil' do
+ expect(diff_file.rich_viewer).to be_nil
+ end
+ end
+
+ context 'when everything is right' do
+ it 'returns the viewer' do
+ expect(diff_file.rich_viewer).to be_a(DiffViewer::Image)
+ end
+ end
+ end
+
+ context 'when the diff file does not have a matching viewer' do
+ let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
+
+ it 'returns nil' do
+ expect(diff_file.rich_viewer).to be_nil
+ end
+ end
+ end
+
+ describe '#rendered_as_text?' do
+ context 'when the simple viewer is text-based' do
+ let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
+
+ context 'when ignoring errors' do
+ context 'when the viewer has render errors' do
+ before do
+ diff_file.diff.too_large!
+ end
+
+ it 'returns true' do
+ expect(diff_file.rendered_as_text?).to be_truthy
+ end
+ end
+
+ context "when the viewer doesn't have render errors" do
+ it 'returns true' do
+ expect(diff_file.rendered_as_text?).to be_truthy
+ end
+ end
+ end
+
+ context 'when not ignoring errors' do
+ context 'when the viewer has render errors' do
+ before do
+ diff_file.diff.too_large!
+ end
+
+ it 'returns false' do
+ expect(diff_file.rendered_as_text?(ignore_errors: false)).to be_falsey
+ end
+ end
+
+ context "when the viewer doesn't have render errors" do
+ it 'returns true' do
+ expect(diff_file.rendered_as_text?(ignore_errors: false)).to be_truthy
+ end
+ end
+ end
+ end
+
+ context 'when the simple viewer is binary' do
+ let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
+
+ it 'returns false' do
+ expect(diff_file.rendered_as_text?).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index 7095104d75c..b3d46e69ccb 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -381,6 +381,54 @@ describe Gitlab::Diff::Position, lib: true do
end
end
+ describe "position for a file in a straight comparison" do
+ let(:diff_refs) do
+ Gitlab::Diff::DiffRefs.new(
+ start_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9', # feature
+ base_sha: '0b4bc9a49b562e85de7cc9e834518ea6828729b9',
+ head_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a' # master
+ )
+ end
+
+ subject do
+ described_class.new(
+ old_path: "files/ruby/feature.rb",
+ new_path: "files/ruby/feature.rb",
+ old_line: 3,
+ new_line: nil,
+ diff_refs: diff_refs
+ )
+ end
+
+ describe "#diff_file" do
+ it "returns the correct diff file" do
+ diff_file = subject.diff_file(project.repository)
+
+ expect(diff_file.deleted_file?).to be true
+ expect(diff_file.old_path).to eq(subject.old_path)
+ expect(diff_file.diff_refs).to eq(subject.diff_refs)
+ end
+ end
+
+ describe "#diff_line" do
+ it "returns the correct diff line" do
+ diff_line = subject.diff_line(project.repository)
+
+ expect(diff_line.removed?).to be true
+ expect(diff_line.old_line).to eq(subject.old_line)
+ expect(diff_line.text).to eq("- puts 'bar'")
+ end
+ end
+
+ describe "#line_code" do
+ it "returns the correct line code" do
+ line_code = Gitlab::Diff::LineCode.generate(subject.file_path, 0, subject.old_line)
+
+ expect(subject.line_code(project.repository)).to eq(line_code)
+ end
+ end
+ end
+
describe "#to_json" do
let(:hash) do
{
diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb
index 24df04e985a..4acf4f047f1 100644
--- a/spec/lib/gitlab/etag_caching/middleware_spec.rb
+++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb
@@ -15,13 +15,13 @@ describe Gitlab::EtagCaching::Middleware do
end
it 'does not add ETag header' do
- _, headers, _ = middleware.call(build_env(path, if_none_match))
+ _, headers, _ = middleware.call(build_request(path, if_none_match))
expect(headers['ETag']).to be_nil
end
it 'passes status code from app' do
- status, _, _ = middleware.call(build_env(path, if_none_match))
+ status, _, _ = middleware.call(build_request(path, if_none_match))
expect(status).to eq app_status_code
end
@@ -39,7 +39,7 @@ describe Gitlab::EtagCaching::Middleware do
expect_any_instance_of(Gitlab::EtagCaching::Store)
.to receive(:touch).and_return('123')
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
end
context 'when If-None-Match header was specified' do
@@ -51,7 +51,7 @@ describe Gitlab::EtagCaching::Middleware do
expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_key_not_found, endpoint: 'issue_notes')
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
end
end
end
@@ -65,7 +65,7 @@ describe Gitlab::EtagCaching::Middleware do
end
it 'returns this value as header' do
- _, headers, _ = middleware.call(build_env(path, if_none_match))
+ _, headers, _ = middleware.call(build_request(path, if_none_match))
expect(headers['ETag']).to eq 'W/"123"'
end
@@ -82,17 +82,17 @@ describe Gitlab::EtagCaching::Middleware do
it 'does not call app' do
expect(app).not_to receive(:call)
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
end
it 'returns status code 304' do
- status, _, _ = middleware.call(build_env(path, if_none_match))
+ status, _, _ = middleware.call(build_request(path, if_none_match))
expect(status).to eq 304
end
it 'returns empty body' do
- _, _, body = middleware.call(build_env(path, if_none_match))
+ _, _, body = middleware.call(build_request(path, if_none_match))
expect(body).to be_empty
end
@@ -103,7 +103,7 @@ describe Gitlab::EtagCaching::Middleware do
expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_cache_hit, endpoint: 'issue_notes')
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
end
context 'when polling is disabled' do
@@ -113,7 +113,7 @@ describe Gitlab::EtagCaching::Middleware do
end
it 'returns status code 429' do
- status, _, _ = middleware.call(build_env(path, if_none_match))
+ status, _, _ = middleware.call(build_request(path, if_none_match))
expect(status).to eq 429
end
@@ -131,7 +131,7 @@ describe Gitlab::EtagCaching::Middleware do
it 'calls app' do
expect(app).to receive(:call).and_return([app_status_code, {}, ['body']])
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
end
it 'tracks "etag_caching_resource_changed" event' do
@@ -142,7 +142,7 @@ describe Gitlab::EtagCaching::Middleware do
expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_resource_changed, endpoint: 'issue_notes')
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
end
end
@@ -160,7 +160,26 @@ describe Gitlab::EtagCaching::Middleware do
expect(Gitlab::Metrics).to receive(:add_event)
.with(:etag_caching_header_missing, endpoint: 'issue_notes')
- middleware.call(build_env(path, if_none_match))
+ middleware.call(build_request(path, if_none_match))
+ end
+ end
+
+ context 'when GitLab instance is using a relative URL' do
+ before do
+ mock_app_response
+ end
+
+ it 'uses full path as cache key' do
+ env = {
+ 'PATH_INFO' => enabled_path,
+ 'SCRIPT_NAME' => '/relative-gitlab'
+ }
+
+ expect_any_instance_of(Gitlab::EtagCaching::Store)
+ .to receive(:get).with("/relative-gitlab#{enabled_path}")
+ .and_return(nil)
+
+ middleware.call(env)
end
end
@@ -173,10 +192,7 @@ describe Gitlab::EtagCaching::Middleware do
.to receive(:get).and_return(value)
end
- def build_env(path, if_none_match)
- {
- 'PATH_INFO' => path,
- 'HTTP_IF_NONE_MATCH' => if_none_match
- }
+ def build_request(path, if_none_match)
+ { 'PATH_INFO' => path, 'HTTP_IF_NONE_MATCH' => if_none_match }
end
end
diff --git a/spec/lib/gitlab/etag_caching/router_spec.rb b/spec/lib/gitlab/etag_caching/router_spec.rb
index 269798c7c9e..f69cb502ca6 100644
--- a/spec/lib/gitlab/etag_caching/router_spec.rb
+++ b/spec/lib/gitlab/etag_caching/router_spec.rb
@@ -2,115 +2,91 @@ require 'spec_helper'
describe Gitlab::EtagCaching::Router do
it 'matches issue notes endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/and-subgroup/here-comes-the-project/noteable/issue/1/notes'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'issue_notes'
end
it 'matches issue title endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/issues/123/realtime_changes'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'issue_title'
end
it 'matches project pipelines endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/pipelines.json'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'project_pipelines'
end
it 'matches commit pipelines endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/commit/aa8260d253a53f73f6c26c734c72fdd600f6e6d4/pipelines.json'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'commit_pipelines'
end
it 'matches new merge request pipelines endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/merge_requests/new.json'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'new_merge_request_pipelines'
end
it 'matches merge request pipelines endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/merge_requests/234/pipelines.json'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'merge_request_pipelines'
end
it 'matches build endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/builds/234.json'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'project_build'
end
it 'does not match blob with confusing name' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/blob/master/pipelines.json'
)
- result = described_class.match(env)
-
expect(result).to be_blank
end
it 'matches the environments path' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/environments.json'
)
- result = described_class.match(env)
expect(result).to be_present
-
expect(result.name).to eq 'environments'
end
it 'matches pipeline#show endpoint' do
- env = build_env(
+ result = described_class.match(
'/my-group/my-project/pipelines/2.json'
)
- result = described_class.match(env)
-
expect(result).to be_present
expect(result.name).to eq 'project_pipeline'
end
-
- def build_env(path)
- { 'PATH_INFO' => path }
- end
end
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 5d416c9eec3..eaec699ad90 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Gfm::ReferenceRewriter do
let(:new_project) { create(:empty_project, name: 'new-project') }
let(:user) { create(:user) }
- before { old_project.team << [user, :reporter] }
+ before do
+ old_project.team << [user, :reporter]
+ end
describe '#rewrite' do
subject do
diff --git a/spec/lib/gitlab/git/compare_spec.rb b/spec/lib/gitlab/git/compare_spec.rb
index 7c45071ec45..4c9f4a28f32 100644
--- a/spec/lib/gitlab/git/compare_spec.rb
+++ b/spec/lib/gitlab/git/compare_spec.rb
@@ -2,8 +2,8 @@ require "spec_helper"
describe Gitlab::Git::Compare, seed_helper: true do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) }
- let(:compare) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, false) }
- let(:compare_straight) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, true) }
+ let(:compare) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, straight: false) }
+ let(:compare_straight) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, straight: true) }
describe '#commits' do
subject do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 26215381cc4..eee4c9eab6d 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -16,7 +16,9 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#root_ref' do
context 'with gitaly disabled' do
- before { allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) }
+ before do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
+ end
it 'calls #discover_default_branch' do
expect(repository).to receive(:discover_default_branch)
@@ -25,8 +27,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ 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)
@@ -120,8 +127,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.not_to include("branch-from-space") }
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ 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)
@@ -158,8 +170,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.not_to include("v5.0.0") }
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ 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)
@@ -1235,47 +1252,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#diffable' do
- info_dir_path = attributes_path = File.join(SEED_STORAGE_PATH, TEST_REPO_PATH, 'info')
- attributes_path = File.join(info_dir_path, 'attributes')
-
- before(:all) do
- FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path)
- File.write(attributes_path, "*.md -diff\n")
- end
-
- it "should return true for files which are text and do not have attributes" do
- blob = Gitlab::Git::Blob.find(
- repository,
- '33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
- 'LICENSE'
- )
- expect(repository.diffable?(blob)).to be_truthy
- end
-
- it "should return false for binary files which do not have attributes" do
- blob = Gitlab::Git::Blob.find(
- repository,
- '33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
- 'files/images/logo-white.png'
- )
- expect(repository.diffable?(blob)).to be_falsey
- end
-
- it "should return false for text files which have been marked as not being diffable in attributes" do
- blob = Gitlab::Git::Blob.find(
- repository,
- '33bcff41c232a11727ac6d660bd4b0c2ba86d63d',
- 'README.md'
- )
- expect(repository.diffable?(blob)).to be_falsey
- end
-
- after(:all) do
- FileUtils.rm_rf(info_dir_path)
- end
- end
-
describe '#tag_exists?' do
it 'returns true for an existing tag' do
tag = repository.tag_names.first
@@ -1321,8 +1297,13 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
context 'with gitaly enabled' do
- before { stub_gitaly }
- after { Gitlab::GitalyClient.clear_stubs! }
+ 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).
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 36d1d777583..3dcc20c48e8 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -60,7 +60,9 @@ describe Gitlab::GitAccess, lib: true do
let(:actor) { deploy_key }
context 'when the DeployKey has access to the project' do
- before { deploy_key.projects << project }
+ before do
+ deploy_key.projects << project
+ end
it 'allows pull access' do
expect { pull_access_check }.not_to raise_error
@@ -84,7 +86,9 @@ describe Gitlab::GitAccess, lib: true do
context 'when actor is a User' do
context 'when the User can read the project' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'allows pull access' do
expect { pull_access_check }.not_to raise_error
@@ -159,7 +163,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe '#check_command_disabled!' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
context 'over http' do
let(:protocol) { 'http' }
@@ -196,7 +202,9 @@ describe Gitlab::GitAccess, lib: true do
describe '#check_download_access!' do
describe 'master permissions' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
context 'pull code' do
it { expect { pull_access_check }.not_to raise_error }
@@ -204,7 +212,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'guest permissions' do
- before { project.team << [user, :guest] }
+ before do
+ project.team << [user, :guest]
+ end
context 'pull code' do
it { expect { pull_access_check }.to raise_unauthorized('You are not allowed to download code from this project.') }
@@ -253,7 +263,9 @@ describe Gitlab::GitAccess, lib: true do
context 'pull code' do
context 'when project is authorized' do
- before { key.projects << project }
+ before do
+ key.projects << project
+ end
it { expect { pull_access_check }.not_to raise_error }
end
@@ -292,7 +304,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'reporter user' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
context 'pull code' do
it { expect { pull_access_check }.not_to raise_error }
@@ -303,7 +317,9 @@ describe Gitlab::GitAccess, lib: true do
let(:user) { create(:admin) }
context 'when member of the project' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
context 'pull code' do
it { expect { pull_access_check }.not_to raise_error }
@@ -328,7 +344,9 @@ describe Gitlab::GitAccess, lib: true do
end
describe '#check_push_access!' do
- before { merge_into_protected_branch }
+ before do
+ merge_into_protected_branch
+ end
let(:unprotected_branch) { 'unprotected_branch' }
let(:changes) do
@@ -457,19 +475,25 @@ describe Gitlab::GitAccess, lib: true do
[%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
context do
- before { create(:protected_branch, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix)
end
context "when developers are allowed to push into the #{protected_branch_type} protected branch" do
- before { create(:protected_branch, :developers_can_push, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :developers_can_push, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
end
context "developers are allowed to merge into the #{protected_branch_type} protected branch" do
- before { create(:protected_branch, :developers_can_merge, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :developers_can_merge, name: protected_branch_name, project: project)
+ end
context "when a merge request exists for the given source/target branch" do
context "when the merge request is in progress" do
@@ -496,13 +520,17 @@ describe Gitlab::GitAccess, lib: true do
end
context "when developers are allowed to push and merge into the #{protected_branch_type} protected branch" do
- before { create(:protected_branch, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :developers_can_merge, :developers_can_push, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: true, push_all: true, merge_into_protected_branch: true }))
end
context "when no one is allowed to push to the #{protected_branch_name} protected branch" do
- before { create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project) }
+ before do
+ create(:protected_branch, :no_one_can_push, name: protected_branch_name, project: project)
+ end
run_permission_checks(permissions_matrix.deep_merge(developer: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false },
master: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false },
@@ -515,7 +543,9 @@ describe Gitlab::GitAccess, lib: true do
let(:authentication_abilities) { build_authentication_abilities }
context 'when project is authorized' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
it { expect { push_access_check }.to raise_unauthorized('You are not allowed to upload code for this project.') }
end
@@ -549,7 +579,9 @@ describe Gitlab::GitAccess, lib: true do
let(:can_push) { true }
context 'when project is authorized' do
- before { key.projects << project }
+ before do
+ key.projects << project
+ end
it { expect { push_access_check }.not_to raise_error }
end
@@ -579,7 +611,9 @@ describe Gitlab::GitAccess, lib: true do
let(:can_push) { false }
context 'when project is authorized' do
- before { key.projects << project }
+ before do
+ key.projects << project
+ end
it { expect { push_access_check }.to raise_unauthorized('This deploy key does not have write access to this project.') }
end
diff --git a/spec/lib/gitlab/gitaly_client/notifications_spec.rb b/spec/lib/gitlab/gitaly_client/notifications_spec.rb
index b87dacb175b..e5c9e06a15e 100644
--- a/spec/lib/gitlab/gitaly_client/notifications_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/notifications_spec.rb
@@ -3,12 +3,13 @@ require 'spec_helper'
describe Gitlab::GitalyClient::Notifications do
describe '#post_receive' do
let(:project) { create(:empty_project) }
- let(:repo_path) { project.repository.path_to_repo }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
subject { described_class.new(project.repository) }
it 'sends a post_receive message' do
expect_any_instance_of(Gitaly::Notifications::Stub).
- to receive(:post_receive).with(gitaly_request_with_repo_path(repo_path))
+ to receive(:post_receive).with(gitaly_request_with_path(storage_name, relative_path))
subject.post_receive
end
diff --git a/spec/lib/gitlab/gitaly_client/ref_spec.rb b/spec/lib/gitlab/gitaly_client/ref_spec.rb
index d8cd2dcbd2a..2ea44ef74b0 100644
--- a/spec/lib/gitlab/gitaly_client/ref_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
describe Gitlab::GitalyClient::Ref do
let(:project) { create(:empty_project) }
- let(:repo_path) { project.repository.path_to_repo }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.path_with_namespace + '.git' }
let(:client) { described_class.new(project.repository) }
before do
@@ -19,7 +20,8 @@ describe Gitlab::GitalyClient::Ref do
describe '#branch_names' do
it 'sends a find_all_branch_names message' do
expect_any_instance_of(Gitaly::Ref::Stub).
- to receive(:find_all_branch_names).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_all_branch_names).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return([])
client.branch_names
@@ -29,7 +31,8 @@ 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).
- to receive(:find_all_tag_names).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_all_tag_names).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return([])
client.tag_names
@@ -39,7 +42,8 @@ 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).
- to receive(:find_default_branch_name).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_default_branch_name).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return(double(name: 'foo'))
client.default_branch_name
@@ -49,7 +53,8 @@ describe Gitlab::GitalyClient::Ref do
describe '#local_branches' do
it 'sends a find_local_branches message' do
expect_any_instance_of(Gitaly::Ref::Stub).
- to receive(:find_local_branches).with(gitaly_request_with_repo_path(repo_path)).
+ to receive(:find_local_branches).
+ with(gitaly_request_with_path(storage_name, relative_path)).
and_return([])
client.local_branches
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 95ecba67532..ce7b18b784a 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -5,7 +5,9 @@ require 'spec_helper'
describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
describe '.stub' do
# Notice that this is referring to gRPC "stubs", not rspec stubs
- before { described_class.clear_stubs! }
+ before do
+ described_class.clear_stubs!
+ end
context 'when passed a UNIX socket address' do
it 'passes the address as-is to GRPC' do
@@ -41,7 +43,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
let(:real_feature_name) { "gitaly_#{feature_name}" }
context 'when Gitaly is disabled' do
- before { allow(described_class).to receive(:enabled?).and_return(false) }
+ before do
+ allow(described_class).to receive(:enabled?).and_return(false)
+ end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name)).to be(false)
@@ -66,7 +70,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to disable" do
- before { Feature.get(real_feature_name).disable }
+ before do
+ Feature.get(real_feature_name).disable
+ end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
@@ -74,7 +80,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to enable" do
- before { Feature.get(real_feature_name).enable }
+ before do
+ Feature.get(real_feature_name).enable
+ end
it 'returns true' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(true)
@@ -82,7 +90,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to a percentage of time" do
- before { Feature.get(real_feature_name).enable_percentage_of_time(70) }
+ before do
+ Feature.get(real_feature_name).enable_percentage_of_time(70)
+ end
it 'bases the result on pseudo-random numbers' do
expect(Random).to receive(:rand).and_return(0.3)
@@ -104,7 +114,9 @@ describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do
end
context "when the feature flag is set to disable" do
- before { Feature.get(real_feature_name).disable }
+ before do
+ Feature.get(real_feature_name).disable
+ end
it 'returns false' do
expect(described_class.feature_enabled?(feature_name, status: feature_status)).to be(false)
diff --git a/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb
new file mode 100644
index 00000000000..ed757ed60d8
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/prometheus_text_format_spec.rb
@@ -0,0 +1,41 @@
+describe Gitlab::HealthChecks::PrometheusTextFormat do
+ let(:metric_class) { Gitlab::HealthChecks::Metric }
+ subject { described_class.new }
+
+ describe '#marshal' do
+ let(:sample_metrics) do
+ [metric_class.new('metric1', 1),
+ metric_class.new('metric2', 2)]
+ end
+
+ it 'marshal to text with non repeating type definition' do
+ expected = <<-EXPECTED.strip_heredoc
+ # TYPE metric1 gauge
+ metric1 1
+ # TYPE metric2 gauge
+ metric2 2
+ EXPECTED
+
+ expect(subject.marshal(sample_metrics)).to eq(expected)
+ end
+
+ context 'metrics where name repeats' do
+ let(:sample_metrics) do
+ [metric_class.new('metric1', 1),
+ metric_class.new('metric1', 2),
+ metric_class.new('metric2', 3)]
+ end
+
+ it 'marshal to text with non repeating type definition' do
+ expected = <<-EXPECTED.strip_heredoc
+ # TYPE metric1 gauge
+ metric1 1
+ metric1 2
+ # TYPE metric2 gauge
+ metric2 3
+ EXPECTED
+ expect(subject.marshal(sample_metrics)).to eq(expected)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index a20cef3b000..fdc5b484ef1 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -7,30 +7,6 @@ describe Gitlab::Highlight, lib: true do
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
- describe '.highlight_lines' do
- let(:lines) do
- Gitlab::Highlight.highlight_lines(project.repository, commit.id, 'files/ruby/popen.rb')
- end
-
- it 'highlights all the lines properly' do
- expect(lines[4]).to eq(%Q{<span id="LC5" class="line" lang="ruby"> <span class="kp">extend</span> <span class="nb">self</span></span>\n})
- expect(lines[21]).to eq(%Q{<span id="LC22" class="line" lang="ruby"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>\n})
- expect(lines[26]).to eq(%Q{<span id="LC27" class="line" lang="ruby"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>\n})
- end
-
- describe 'with CRLF' do
- let(:branch) { 'crlf-diff' }
- let(:blob) { repository.blob_at_branch(branch, path) }
- let(:lines) do
- Gitlab::Highlight.highlight_lines(project.repository, 'crlf-diff', 'files/whitespace')
- end
-
- it 'strips extra LFs' do
- expect(lines[0]).to eq("<span id=\"LC1\" class=\"line\" lang=\"plaintext\">test </span>")
- end
- end
- end
-
describe 'custom highlighting from .gitattributes' do
let(:branch) { 'gitattributes' }
let(:blob) { repository.blob_at_branch(branch, path) }
@@ -39,7 +15,9 @@ describe Gitlab::Highlight, lib: true do
Gitlab::Highlight.new(blob.path, blob.data, repository: repository)
end
- before { project.change_head('gitattributes') }
+ before do
+ project.change_head('gitattributes')
+ end
describe 'basic language selection' do
let(:path) { 'custom-highlighting/test.gitlab-custom' }
@@ -59,6 +37,19 @@ describe Gitlab::Highlight, lib: true do
end
describe '#highlight' do
+ describe 'with CRLF' do
+ let(:branch) { 'crlf-diff' }
+ 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
+ end
+
+ it 'strips extra LFs' do
+ expect(lines[0]).to eq("<span id=\"LC1\" class=\"line\" lang=\"plaintext\">test </span>")
+ end
+ end
+
it 'links dependencies via DependencyLinker' do
expect(Gitlab::DependencyLinker).to receive(:link).
with('file.name', 'Contents', anything).and_call_original
diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb
index a3dbeaa3753..0dba4132101 100644
--- a/spec/lib/gitlab/i18n_spec.rb
+++ b/spec/lib/gitlab/i18n_spec.rb
@@ -4,7 +4,9 @@ describe Gitlab::I18n, lib: true do
let(:user) { create(:user, preferred_language: 'es') }
describe '.locale=' do
- after { described_class.use_default_locale }
+ after do
+ described_class.use_default_locale
+ end
it 'sets the locale based on current user preferred language' do
described_class.locale = user.preferred_language
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 21296a36729..412eb33b35b 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -91,6 +91,7 @@ merge_request_diff:
pipelines:
- project
- user
+- stages
- statuses
- builds
- trigger_requests
@@ -104,9 +105,15 @@ pipelines:
- artifacts
- pipeline_schedule
- merge_requests
+stages:
+- project
+- pipeline
+- statuses
+- builds
statuses:
- project
- pipeline
+- stage
- user
- auto_canceled_by
variables:
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 54ce8051f30..50ff6ecc1e0 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -92,6 +92,7 @@ Milestone:
ProjectSnippet:
- id
- title
+- description
- content
- author_id
- project_id
@@ -174,6 +175,7 @@ MergeRequestDiff:
Ci::Pipeline:
- id
- project_id
+- source
- ref
- sha
- before_sha
@@ -191,7 +193,13 @@ Ci::Pipeline:
- lock_version
- auto_canceled_by_id
- pipeline_schedule_id
-- source
+Ci::Stage:
+- id
+- name
+- project_id
+- pipeline_id
+- created_at
+- updated_at
CommitStatus:
- id
- project_id
@@ -213,6 +221,7 @@ CommitStatus:
- stage
- trigger_request_id
- stage_idx
+- stage_id
- tag
- ref
- user_id
diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb
index 91f9d06b85a..e8c599a95ee 100644
--- a/spec/lib/gitlab/kubernetes_spec.rb
+++ b/spec/lib/gitlab/kubernetes_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe Gitlab::Kubernetes do
+ include KubernetesHelpers
include described_class
describe '#container_exec_url' do
@@ -36,4 +37,13 @@ describe Gitlab::Kubernetes do
it { expect(result.query).to match(/\Acontainer=container\+1&/) }
end
end
+
+ describe '#filter_by_label' do
+ it 'returns matching labels' do
+ matching_items = [kube_pod(app: 'foo')]
+ items = matching_items + [kube_pod]
+
+ expect(filter_by_label(items, app: 'foo')).to eq(matching_items)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index 563c074017a..9454878b057 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -74,13 +74,17 @@ describe Gitlab::LDAP::Adapter, lib: true do
subject { adapter.dn_matches_filter?(:dn, :filter) }
context "when the search result is non-empty" do
- before { allow(adapter).to receive(:ldap_search).and_return([:foo]) }
+ before do
+ allow(adapter).to receive(:ldap_search).and_return([:foo])
+ end
it { is_expected.to be_truthy }
end
context "when the search result is empty" do
- before { allow(adapter).to receive(:ldap_search).and_return([]) }
+ before do
+ allow(adapter).to receive(:ldap_search).and_return([])
+ end
it { is_expected.to be_falsey }
end
@@ -91,13 +95,17 @@ describe Gitlab::LDAP::Adapter, lib: true do
context "when the search is successful" do
context "and the result is non-empty" do
- before { allow(ldap).to receive(:search).and_return([:foo]) }
+ before do
+ allow(ldap).to receive(:search).and_return([:foo])
+ end
it { is_expected.to eq [:foo] }
end
context "and the result is empty" do
- before { allow(ldap).to receive(:search).and_return([]) }
+ before do
+ allow(ldap).to receive(:search).and_return([])
+ end
it { is_expected.to eq [] }
end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index f4aab429931..f0a1dd22fee 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -37,7 +37,7 @@ describe Gitlab::LDAP::User, lib: true do
end
it "does not mark existing ldap user as changed" do
- create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', ldap_email: true)
+ create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', external_email: true, email_provider: 'ldapmain')
expect(ldap_user.changed?).to be_falsey
end
end
@@ -141,8 +141,12 @@ describe Gitlab::LDAP::User, lib: true do
expect(ldap_user.gl_user.email).to eq(info[:email])
end
- it "has ldap_email set to true" do
- expect(ldap_user.gl_user.ldap_email?).to be(true)
+ it "has external_email set to true" do
+ expect(ldap_user.gl_user.external_email?).to be(true)
+ end
+
+ it "has email_provider set to provider" do
+ expect(ldap_user.gl_user.email_provider).to eql 'ldapmain'
end
end
@@ -155,8 +159,8 @@ describe Gitlab::LDAP::User, lib: true do
expect(ldap_user.gl_user.temp_oauth_email?).to be(true)
end
- it "has ldap_email set to false" do
- expect(ldap_user.gl_user.ldap_email?).to be(false)
+ it "has external_email set to false" do
+ expect(ldap_user.gl_user.external_email?).to be(false)
end
end
end
@@ -169,7 +173,9 @@ describe Gitlab::LDAP::User, lib: true do
context 'signup' do
context 'dont block on create' do
- before { configure_block(false) }
+ before do
+ configure_block(false)
+ end
it do
ldap_user.save
@@ -179,7 +185,9 @@ describe Gitlab::LDAP::User, lib: true do
end
context 'block on create' do
- before { configure_block(true) }
+ before do
+ configure_block(true)
+ end
it do
ldap_user.save
@@ -196,7 +204,9 @@ describe Gitlab::LDAP::User, lib: true do
end
context 'dont block on create' do
- before { configure_block(false) }
+ before do
+ configure_block(false)
+ end
it do
ldap_user.save
@@ -206,7 +216,9 @@ describe Gitlab::LDAP::User, lib: true do
end
context 'block on create' do
- before { configure_block(true) }
+ before do
+ configure_block(true)
+ end
it do
ldap_user.save
diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb
index 208a8d028cd..5a87b906609 100644
--- a/spec/lib/gitlab/metrics_spec.rb
+++ b/spec/lib/gitlab/metrics_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Gitlab::Metrics do
+ include StubENV
+
describe '.settings' do
it 'returns a Hash' do
expect(described_class.settings).to be_an_instance_of(Hash)
@@ -9,7 +11,19 @@ describe Gitlab::Metrics do
describe '.enabled?' do
it 'returns a boolean' do
- expect([true, false].include?(described_class.enabled?)).to eq(true)
+ expect(described_class.enabled?).to be_in([true, false])
+ end
+ end
+
+ describe '.prometheus_metrics_enabled?' do
+ it 'returns a boolean' do
+ expect(described_class.prometheus_metrics_enabled?).to be_in([true, false])
+ end
+ end
+
+ describe '.influx_metrics_enabled?' do
+ it 'returns a boolean' do
+ expect(described_class.influx_metrics_enabled?).to be_in([true, false])
end
end
@@ -177,4 +191,133 @@ describe Gitlab::Metrics do
end
end
end
+
+ shared_examples 'prometheus metrics API' do
+ describe '#counter' do
+ subject { described_class.counter(:couter, 'doc') }
+
+ describe '#increment' do
+ it 'successfully calls #increment without arguments' do
+ expect { subject.increment }.not_to raise_exception
+ end
+
+ it 'successfully calls #increment with 1 argument' do
+ expect { subject.increment({}) }.not_to raise_exception
+ end
+
+ it 'successfully calls #increment with 2 arguments' do
+ expect { subject.increment({}, 1) }.not_to raise_exception
+ end
+ end
+ end
+
+ describe '#summary' do
+ subject { described_class.summary(:summary, 'doc') }
+
+ describe '#observe' do
+ it 'successfully calls #observe with 2 arguments' do
+ expect { subject.observe({}, 2) }.not_to raise_exception
+ end
+ end
+ end
+
+ describe '#gauge' do
+ subject { described_class.gauge(:gauge, 'doc') }
+
+ describe '#set' do
+ it 'successfully calls #set with 2 arguments' do
+ expect { subject.set({}, 1) }.not_to raise_exception
+ end
+ end
+ end
+
+ describe '#histogram' do
+ subject { described_class.histogram(:histogram, 'doc') }
+
+ describe '#observe' do
+ it 'successfully calls #observe with 2 arguments' do
+ expect { subject.observe({}, 2) }.not_to raise_exception
+ end
+ end
+ end
+ end
+
+ context 'prometheus metrics disabled' do
+ before do
+ allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(false)
+ end
+
+ it_behaves_like 'prometheus metrics API'
+
+ describe '#null_metric' do
+ subject { described_class.provide_metric(:test) }
+
+ it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#counter' do
+ subject { described_class.counter(:counter, 'doc') }
+
+ it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#summary' do
+ subject { described_class.summary(:summary, 'doc') }
+
+ it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#gauge' do
+ subject { described_class.gauge(:gauge, 'doc') }
+
+ it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#histogram' do
+ subject { described_class.histogram(:histogram, 'doc') }
+
+ it { is_expected.to be_a(Gitlab::Metrics::NullMetric) }
+ end
+ end
+
+ context 'prometheus metrics enabled' do
+ let(:metrics_multiproc_dir) { Dir.mktmpdir }
+
+ before do
+ stub_const('Prometheus::Client::Multiprocdir', metrics_multiproc_dir)
+ allow(described_class).to receive(:prometheus_metrics_enabled?).and_return(true)
+ end
+
+ it_behaves_like 'prometheus metrics API'
+
+ describe '#null_metric' do
+ subject { described_class.provide_metric(:test) }
+
+ it { is_expected.to be_nil }
+ end
+
+ describe '#counter' do
+ subject { described_class.counter(:name, 'doc') }
+
+ it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#summary' do
+ subject { described_class.summary(:name, 'doc') }
+
+ it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#gauge' do
+ subject { described_class.gauge(:name, 'doc') }
+
+ it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
+ end
+
+ describe '#histogram' do
+ subject { described_class.histogram(:name, 'doc') }
+
+ it { is_expected.not_to be_a(Gitlab::Metrics::NullMetric) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
index 168090d5b5c..88107536c9e 100644
--- a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
+++ b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Middleware::RailsQueueDuration do
let(:env) { {} }
let(:transaction) { double(:transaction) }
- before { expect(app).to receive(:call).with(env).and_return('yay') }
+ before do
+ expect(app).to receive(:call).with(env).and_return('yay')
+ end
describe '#call' do
it 'calls the app when metrics are disabled' do
@@ -15,7 +17,9 @@ describe Gitlab::Middleware::RailsQueueDuration do
end
context 'when metrics are enabled' do
- before { allow(Gitlab::Metrics).to receive(:current_transaction).and_return(transaction) }
+ before do
+ allow(Gitlab::Metrics).to receive(:current_transaction).and_return(transaction)
+ end
it 'calls the app when metrics are enabled but no timing header is found' do
expect(middleware.call(env)).to eq('yay')
diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
index 8aaeb5779d3..19ab17419fc 100644
--- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
@@ -55,7 +55,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do
end
context 'email not provided' do
- before { info_hash.delete(:email) }
+ before do
+ info_hash.delete(:email)
+ end
it 'generates a temp email' do
expect( auth_hash.email).to start_with('temp-email-for-oauth')
@@ -63,7 +65,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do
end
context 'username not provided' do
- before { info_hash.delete(:nickname) }
+ before do
+ info_hash.delete(:nickname)
+ end
it 'takes the first part of the email as username' do
expect(auth_hash.username).to eql 'onur.kucuk_ABC-123'
@@ -71,7 +75,9 @@ describe Gitlab::OAuth::AuthHash, lib: true do
end
context 'name not provided' do
- before { info_hash.delete(:name) }
+ before do
+ info_hash.delete(:name)
+ end
it 'concats first and lastname as the name' do
expect(auth_hash.name).to eql name_utf8
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 828c953197d..ea29cb9caf1 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -28,11 +28,11 @@ describe Gitlab::OAuth::User, lib: true do
end
end
- describe '#save' do
- def stub_omniauth_config(messages)
- allow(Gitlab.config.omniauth).to receive_messages(messages)
- end
+ def stub_omniauth_config(messages)
+ allow(Gitlab.config.omniauth).to receive_messages(messages)
+ end
+ describe '#save' do
def stub_ldap_config(messages)
allow(Gitlab::LDAP::Config).to receive_messages(messages)
end
@@ -112,7 +112,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'with new allow_single_sign_on enabled syntax' do
- before { stub_omniauth_config(allow_single_sign_on: ['twitter']) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['twitter'])
+ end
it "creates a user from Omniauth" do
oauth_user.save
@@ -125,7 +127,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context "with old allow_single_sign_on enabled syntax" do
- before { stub_omniauth_config(allow_single_sign_on: true) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: true)
+ end
it "creates a user from Omniauth" do
oauth_user.save
@@ -138,14 +142,20 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'with new allow_single_sign_on disabled syntax' do
- before { stub_omniauth_config(allow_single_sign_on: []) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: [])
+ end
+
it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
end
context 'with old allow_single_sign_on disabled (Default)' do
- before { stub_omniauth_config(allow_single_sign_on: false) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: false)
+ end
+
it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
@@ -153,21 +163,30 @@ describe Gitlab::OAuth::User, lib: true do
end
context "with auto_link_ldap_user disabled (default)" do
- before { stub_omniauth_config(auto_link_ldap_user: false) }
+ before do
+ stub_omniauth_config(auto_link_ldap_user: false)
+ end
+
include_examples "to verify compliance with allow_single_sign_on"
end
context "with auto_link_ldap_user enabled" do
- before { stub_omniauth_config(auto_link_ldap_user: true) }
+ before do
+ stub_omniauth_config(auto_link_ldap_user: true)
+ end
context "and no LDAP provider defined" do
- before { stub_ldap_config(providers: []) }
+ before do
+ stub_ldap_config(providers: [])
+ end
include_examples "to verify compliance with allow_single_sign_on"
end
context "and at least one LDAP provider is defined" do
- before { stub_ldap_config(providers: %w(ldapmain)) }
+ before do
+ stub_ldap_config(providers: %w(ldapmain))
+ end
context "and a corresponding LDAP person" do
before do
@@ -238,7 +257,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context "and no corresponding LDAP person" do
- before { allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) }
+ before do
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil)
+ end
include_examples "to verify compliance with allow_single_sign_on"
end
@@ -248,11 +269,16 @@ describe Gitlab::OAuth::User, lib: true do
describe 'blocking' do
let(:provider) { 'twitter' }
- before { stub_omniauth_config(allow_single_sign_on: ['twitter']) }
+
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['twitter'])
+ end
context 'signup with omniauth only' do
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -262,7 +288,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -284,7 +312,9 @@ describe Gitlab::OAuth::User, lib: true do
context "and no account for the LDAP user" do
context 'dont block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -294,7 +324,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -308,7 +340,9 @@ describe Gitlab::OAuth::User, lib: true do
let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'ldapmain', username: 'john') }
context 'dont block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -318,7 +352,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -336,7 +372,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -346,7 +384,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -356,7 +396,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'dont block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: false)
+ end
it do
oauth_user.save
@@ -366,7 +408,9 @@ describe Gitlab::OAuth::User, lib: true do
end
context 'block on create (LDAP)' do
- before { allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true) }
+ before do
+ allow_any_instance_of(Gitlab::LDAP::Config).to receive_messages(block_auto_created_users: true)
+ end
it do
oauth_user.save
@@ -377,4 +421,40 @@ describe Gitlab::OAuth::User, lib: true do
end
end
end
+
+ describe 'updating email' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_config(sync_email_from_provider: 'my-provider')
+ end
+
+ context "when provider sets an email" do
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ end
+
+ it "has external_email set to true" do
+ expect(gl_user.external_email?).to be(true)
+ end
+
+ it "has email_provider set to provider" do
+ expect(gl_user.email_provider).to eql 'my-provider'
+ end
+ end
+
+ context "when provider doesn't set an email" do
+ before do
+ info_hash.delete(:email)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.email).not_to eq(info_hash[:email])
+ end
+
+ it "has external_email set to false" do
+ expect(gl_user.external_email?).to be(false)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/redis_spec.rb b/spec/lib/gitlab/redis_spec.rb
index 8b77c925705..593aa5038ad 100644
--- a/spec/lib/gitlab/redis_spec.rb
+++ b/spec/lib/gitlab/redis_spec.rb
@@ -108,11 +108,18 @@ describe Gitlab::Redis do
end
describe '.with' do
- before { clear_pool }
- after { clear_pool }
+ before do
+ clear_pool
+ end
+
+ after do
+ clear_pool
+ end
context 'when running not on sidekiq workers' do
- before { allow(Sidekiq).to receive(:server?).and_return(false) }
+ before do
+ allow(Sidekiq).to receive(:server?).and_return(false)
+ end
it 'instantiates a connection pool with size 5' do
expect(ConnectionPool).to receive(:new).with(size: 5).and_call_original
diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb
index b106d156b75..a4d2367b72a 100644
--- a/spec/lib/gitlab/saml/user_spec.rb
+++ b/spec/lib/gitlab/saml/user_spec.rb
@@ -31,11 +31,17 @@ describe Gitlab::Saml::User, lib: true do
allow(Gitlab::Saml::Config).to receive_messages({ options: { name: 'saml', groups_attribute: 'groups', external_groups: groups, args: {} } })
end
- before { stub_basic_saml_config }
+ before do
+ stub_basic_saml_config
+ end
describe 'account exists on server' do
- before { stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) }
+ before do
+ stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true })
+ end
+
let!(:existing_user) { create(:user, email: 'john@mail.com', username: 'john') }
+
context 'and should bind with SAML' do
it 'adds the SAML identity to the existing user' do
saml_user.save
@@ -57,7 +63,10 @@ describe Gitlab::Saml::User, lib: true do
end
end
- before { stub_saml_group_config(%w(Interns)) }
+ before do
+ stub_saml_group_config(%w(Interns))
+ end
+
context 'are defined but the user does not belong there' do
it 'does not mark the user as external' do
saml_user.save
@@ -80,7 +89,9 @@ describe Gitlab::Saml::User, lib: true do
describe 'no account exists on server' do
shared_examples 'to verify compliance with allow_single_sign_on' do
context 'with allow_single_sign_on enabled' do
- before { stub_omniauth_config(allow_single_sign_on: ['saml']) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['saml'])
+ end
it 'creates a user from SAML' do
saml_user.save
@@ -93,14 +104,20 @@ describe Gitlab::Saml::User, lib: true do
end
context 'with allow_single_sign_on default (["saml"])' do
- before { stub_omniauth_config(allow_single_sign_on: ['saml']) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: ['saml'])
+ end
+
it 'does not throw an error' do
expect{ saml_user.save }.not_to raise_error
end
end
context 'with allow_single_sign_on disabled' do
- before { stub_omniauth_config(allow_single_sign_on: false) }
+ before do
+ stub_omniauth_config(allow_single_sign_on: false)
+ end
+
it 'throws an error' do
expect{ saml_user.save }.to raise_error StandardError
end
@@ -128,15 +145,22 @@ describe Gitlab::Saml::User, lib: true do
end
context 'with auto_link_ldap_user disabled (default)' do
- before { stub_omniauth_config({ auto_link_ldap_user: false, auto_link_saml_user: false, allow_single_sign_on: ['saml'] }) }
+ before do
+ stub_omniauth_config({ auto_link_ldap_user: false, auto_link_saml_user: false, allow_single_sign_on: ['saml'] })
+ end
+
include_examples 'to verify compliance with allow_single_sign_on'
end
context 'with auto_link_ldap_user enabled' do
- before { stub_omniauth_config({ auto_link_ldap_user: true, auto_link_saml_user: false }) }
+ before do
+ stub_omniauth_config({ auto_link_ldap_user: true, auto_link_saml_user: false })
+ end
context 'and at least one LDAP provider is defined' do
- before { stub_ldap_config(providers: %w(ldapmain)) }
+ before do
+ stub_ldap_config(providers: %w(ldapmain))
+ end
context 'and a corresponding LDAP person' do
before do
@@ -239,11 +263,15 @@ describe Gitlab::Saml::User, lib: true do
end
describe 'blocking' do
- before { stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true }) }
+ before do
+ stub_omniauth_config({ allow_single_sign_on: ['saml'], auto_link_saml_user: true })
+ end
context 'signup with SAML only' do
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it 'does not block the user' do
saml_user.save
@@ -253,7 +281,9 @@ describe Gitlab::Saml::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it 'blocks user' do
saml_user.save
@@ -270,7 +300,9 @@ describe Gitlab::Saml::User, lib: true do
end
context 'dont block on create' do
- before { stub_omniauth_config(block_auto_created_users: false) }
+ before do
+ stub_omniauth_config(block_auto_created_users: false)
+ end
it do
saml_user.save
@@ -280,7 +312,9 @@ describe Gitlab::Saml::User, lib: true do
end
context 'block on create' do
- before { stub_omniauth_config(block_auto_created_users: true) }
+ before do
+ stub_omniauth_config(block_auto_created_users: true)
+ end
it do
saml_user.save
diff --git a/spec/lib/gitlab/serializer/pagination_spec.rb b/spec/lib/gitlab/serializer/pagination_spec.rb
index 519eb1b274f..1bc6536439e 100644
--- a/spec/lib/gitlab/serializer/pagination_spec.rb
+++ b/spec/lib/gitlab/serializer/pagination_spec.rb
@@ -22,7 +22,9 @@ describe Gitlab::Serializer::Pagination do
let(:params) { { page: 1, per_page: 2 } }
context 'when a multiple resources are present in relation' do
- before { create_list(:user, 3) }
+ before do
+ create_list(:user, 3)
+ end
it 'correctly paginates the resource' do
expect(subject.count).to be 2
diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb
index 329d1d74970..bf45c8d16d6 100644
--- a/spec/lib/gitlab/template/issue_template_spec.rb
+++ b/spec/lib/gitlab/template/issue_template_spec.rb
@@ -52,7 +52,10 @@ describe Gitlab::Template::IssueTemplate do
context 'when repo is bare or empty' do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "returns empty array" do
templates = subject.by_category('', empty_project)
@@ -77,7 +80,9 @@ describe Gitlab::Template::IssueTemplate do
context "when repo is empty" do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "raises file not found" do
issue_template = subject.new('.gitlab/issue_templates/not_existent.md', empty_project)
diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb
index 2b0056d9bab..8479f92c8df 100644
--- a/spec/lib/gitlab/template/merge_request_template_spec.rb
+++ b/spec/lib/gitlab/template/merge_request_template_spec.rb
@@ -52,7 +52,10 @@ describe Gitlab::Template::MergeRequestTemplate do
context 'when repo is bare or empty' do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "returns empty array" do
templates = subject.by_category('', empty_project)
@@ -77,7 +80,9 @@ describe Gitlab::Template::MergeRequestTemplate do
context "when repo is empty" do
let(:empty_project) { create(:empty_project) }
- before { empty_project.add_user(user, Gitlab::Access::MASTER) }
+ before do
+ empty_project.add_user(user, Gitlab::Access::MASTER)
+ end
it "raises file not found" do
issue_template = subject.new('.gitlab/merge_request_templates/not_existent.md', empty_project)
diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb
new file mode 100644
index 00000000000..109559bb01c
--- /dev/null
+++ b/spec/lib/gitlab/uploads_transfer_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+describe Gitlab::UploadsTransfer do
+ it 'leaves avatar uploads where they are' do
+ project_with_avatar = create(:empty_project, :with_avatar)
+
+ described_class.new.rename_namespace('project', 'project-renamed')
+
+ expect(File.exist?(project_with_avatar.avatar.path)).to be_truthy
+ end
+end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 3fe8cf43934..e8a37e8d77b 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -97,6 +97,17 @@ describe Gitlab::UrlBuilder, lib: true do
end
end
+ context 'on a PersonalSnippet' do
+ it 'returns a proper URL' do
+ personal_snippet = create(:personal_snippet)
+ note = build_stubbed(:note_on_personal_snippet, noteable: personal_snippet)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/snippets/#{note.noteable_id}#note_#{note.id}"
+ end
+ end
+
context 'on another object' do
it 'returns a proper URL' do
project = build_stubbed(:empty_project)
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index b1999409170..ad19998dff4 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -212,7 +212,7 @@ describe Gitlab::Workhorse, lib: true do
it 'includes a Repository param' do
repo_param = { Repository: {
- path: repo_path,
+ path: '', # deprecated field; grpc automatically creates it anyway
storage_name: 'default',
relative_path: project.full_path + '.git'
} }
diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb
index 18726754517..e7022bd06f8 100644
--- a/spec/lib/json_web_token/rsa_token_spec.rb
+++ b/spec/lib/json_web_token/rsa_token_spec.rb
@@ -15,11 +15,15 @@ describe JSONWebToken::RSAToken do
let(:rsa_token) { described_class.new(nil) }
let(:rsa_encoded) { rsa_token.encoded }
- before { allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key) }
+ before do
+ allow_any_instance_of(described_class).to receive(:key).and_return(rsa_key)
+ end
context 'token' do
context 'for valid key to be validated' do
- before { rsa_token['key'] = 'value' }
+ before do
+ rsa_token['key'] = 'value'
+ end
subject { JWT.decode(rsa_encoded, rsa_key) }
diff --git a/spec/lib/json_web_token/token_spec.rb b/spec/lib/json_web_token/token_spec.rb
index 3d955e4d774..d7e7560d962 100644
--- a/spec/lib/json_web_token/token_spec.rb
+++ b/spec/lib/json_web_token/token_spec.rb
@@ -3,7 +3,10 @@ describe JSONWebToken::Token do
context 'custom parameters' do
let(:value) { 'value' }
- before { token[:key] = value }
+
+ before do
+ token[:key] = value
+ end
it { expect(token[:key]).to eq(value) }
it { expect(token.payload).to include(key: value) }
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index ec6f6c42eac..980b24370d0 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -130,8 +130,13 @@ describe Notify do
end
context 'with a preferred language' do
- before { Gitlab::I18n.locale = :es }
- after { Gitlab::I18n.use_default_locale }
+ before do
+ Gitlab::I18n.locale = :es
+ end
+
+ after do
+ Gitlab::I18n.use_default_locale
+ end
it 'always generates the email using the default language' do
is_expected.to have_body_text('foo, bar, and baz')
@@ -581,7 +586,9 @@ describe Notify do
let(:project) { create(:project, :repository) }
let(:commit) { project.commit }
- before(:each) { allow(note).to receive(:noteable).and_return(commit) }
+ before do
+ allow(note).to receive(:noteable).and_return(commit)
+ end
subject { described_class.note_commit_email(recipient.id, note.id) }
@@ -603,7 +610,10 @@ 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}") }
- before(:each) { allow(note).to receive(:noteable).and_return(merge_request) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(merge_request)
+ end
subject { described_class.note_merge_request_email(recipient.id, note.id) }
@@ -625,7 +635,10 @@ 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}") }
- before(:each) { allow(note).to receive(:noteable).and_return(issue) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(issue)
+ end
subject { described_class.note_issue_email(recipient.id, note.id) }
@@ -687,7 +700,9 @@ describe Notify do
let(:commit) { project.commit }
let(:note) { create(:discussion_note_on_commit, commit_id: commit.id, project: project, author: note_author) }
- before(:each) { allow(note).to receive(:noteable).and_return(commit) }
+ before do
+ allow(note).to receive(:noteable).and_return(commit)
+ end
subject { described_class.note_commit_email(recipient.id, note.id) }
@@ -711,7 +726,10 @@ describe Notify 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}") }
- before(:each) { allow(note).to receive(:noteable).and_return(merge_request) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(merge_request)
+ end
subject { described_class.note_merge_request_email(recipient.id, note.id) }
@@ -735,7 +753,10 @@ describe Notify 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}") }
- before(:each) { allow(note).to receive(:noteable).and_return(issue) }
+
+ before do
+ allow(note).to receive(:noteable).and_return(issue)
+ end
subject { described_class.note_issue_email(recipient.id, note.id) }
diff --git a/spec/migrations/README.md b/spec/migrations/README.md
new file mode 100644
index 00000000000..05d4f35db72
--- /dev/null
+++ b/spec/migrations/README.md
@@ -0,0 +1,87 @@
+# Testing migrations
+
+In order to reliably test a migration, we need to test it against a database
+schema that this migration has been written for. In order to achieve that we
+have some _migration helpers_ and RSpec test tag, called `:migration`.
+
+If you want to write a test for a migration consider adding `:migration` tag to
+the test signature, like `describe SomeMigrationClass, :migration`.
+
+## How does it work?
+
+Adding a `:migration` tag to a test signature injects a few before / after
+hooks to the test.
+
+The most important change is that adding a `:migration` tag adds a `before`
+hook that will revert all migrations to the point that a migration under test
+is not yet migrated.
+
+In other words, our custom RSpec hooks will find a previous migration, and
+migrate the database **down** to the previous migration version.
+
+With this approach you can test a migration against a database schema that this
+migration has been written for.
+
+Use `migrate!` helper to run the migration that is under test.
+
+The `after` hook will migrate the database **up** and reinstitutes the latest
+schema version, so that the process does not affect subsequent specs and
+ensures proper isolation.
+
+## Available helpers
+
+Use `table` helper to create a temporary `ActiveRecord::Base` derived model
+for a table.
+
+Use `migrate!` helper to run the migration that is under test. It will not only
+run migration, but will also bump the schema version in the `schema_migrations`
+table. It is necessary because in the `after` hook we trigger the rest of
+the migrations, and we need to know where to start.
+
+See `spec/support/migrations_helpers.rb` for all the available helpers.
+
+## An example
+
+```ruby
+require 'spec_helper'
+
+# Load a migration class.
+
+require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb')
+
+describe MigratePipelineStages, :migration do
+
+ # Create test data - pipeline and CI/CD jobs.
+
+ let(:jobs) { table(:ci_builds) }
+ let(:stages) { table(:ci_stages) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:projects) { table(:projects) }
+
+ before do
+ projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
+ pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
+ 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: 1, stage: 'test')
+ end
+
+ # Test the migration.
+
+ it 'correctly migrates pipeline stages' do
+ expect(stages.count).to be_zero
+
+ migrate!
+
+ expect(stages.count).to eq 2
+ expect(stages.all.pluck(:name)).to match_array %w[test build]
+ end
+end
+```
+
+## Best practices
+
+1. Use only one test example per migration unless there is a good reason to
+use more.
+1. Note that this type of tests do not run within the transaction, we use
+a truncation database cleanup strategy. Do not depend on transaction being
+present.
diff --git a/spec/migrations/clean_upload_symlinks_spec.rb b/spec/migrations/clean_upload_symlinks_spec.rb
new file mode 100644
index 00000000000..cecb3ddac53
--- /dev/null
+++ b/spec/migrations/clean_upload_symlinks_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170406111121_clean_upload_symlinks.rb')
+
+describe CleanUploadSymlinks do
+ let(:migration) { described_class.new }
+ let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_uploads_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, 'user') }
+ let(:symlink_path) { File.join(uploads_dir, 'user') }
+
+ 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/convert_custom_notification_settings_to_columns_spec.rb b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb
new file mode 100644
index 00000000000..1396d12e5a9
--- /dev/null
+++ b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb
@@ -0,0 +1,118 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170607121233_convert_custom_notification_settings_to_columns')
+
+describe ConvertCustomNotificationSettingsToColumns, :migration do
+ let(:settings_params) do
+ [
+ { level: 0, events: [:new_note] }, # disabled, single event
+ { level: 3, events: [:new_issue, :reopen_issue, :close_issue, :reassign_issue] }, # global, multiple events
+ { level: 5, events: described_class::EMAIL_EVENTS }, # custom, all events
+ { level: 5, events: [] } # custom, no events
+ ]
+ end
+
+ let(:notification_settings_before) do
+ settings_params.map do |params|
+ events = {}
+
+ params[:events].each do |event|
+ events[event] = true
+ end
+
+ user = create(:user)
+ create_params = { user_id: user.id, level: params[:level], events: events }
+ notification_setting = described_class::NotificationSetting.create(create_params)
+
+ [notification_setting, params]
+ end
+ end
+
+ let(:notification_settings_after) do
+ settings_params.map do |params|
+ events = {}
+
+ params[:events].each do |event|
+ events[event] = true
+ end
+
+ user = create(:user)
+ create_params = events.merge(user_id: user.id, level: params[:level])
+ notification_setting = described_class::NotificationSetting.create(create_params)
+
+ [notification_setting, params]
+ end
+ end
+
+ describe '#up' do
+ it 'migrates all settings where a custom event is enabled, even if they are not currently using the custom level' do
+ notification_settings_before
+
+ described_class.new.up
+
+ notification_settings_before.each do |(notification_setting, params)|
+ notification_setting.reload
+
+ expect(notification_setting.read_attribute_before_type_cast(:events)).to be_nil
+ expect(notification_setting.level).to eq(params[:level])
+
+ described_class::EMAIL_EVENTS.each do |event|
+ # We don't set the others to false, just let them default to nil
+ expected = params[:events].include?(event) || nil
+
+ expect(notification_setting.read_attribute(event)).to eq(expected)
+ end
+ end
+ end
+ end
+
+ describe '#down' do
+ it 'creates a custom events hash for all settings where at least one event is enabled' do
+ notification_settings_after
+
+ described_class.new.down
+
+ notification_settings_after.each do |(notification_setting, params)|
+ notification_setting.reload
+
+ expect(notification_setting.level).to eq(params[:level])
+
+ if params[:events].empty?
+ # We don't migrate empty settings
+ expect(notification_setting.events).to eq({})
+ else
+ described_class::EMAIL_EVENTS.each do |event|
+ expected = params[:events].include?(event)
+
+ expect(notification_setting.events[event]).to eq(expected)
+ expect(notification_setting.read_attribute(event)).to be_nil
+ end
+ end
+ end
+ end
+
+ it 'reverts the database to the state it was in before' do
+ notification_settings_before
+
+ described_class.new.up
+ described_class.new.down
+
+ notification_settings_before.each do |(notification_setting, params)|
+ notification_setting.reload
+
+ expect(notification_setting.level).to eq(params[:level])
+
+ if params[:events].empty?
+ # We don't migrate empty settings
+ expect(notification_setting.events).to eq({})
+ else
+ described_class::EMAIL_EVENTS.each do |event|
+ expected = params[:events].include?(event)
+
+ expect(notification_setting.events[event]).to eq(expected)
+ expect(notification_setting.read_attribute(event)).to be_nil
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/migrate_build_stage_reference_spec.rb b/spec/migrations/migrate_build_stage_reference_spec.rb
new file mode 100644
index 00000000000..80b321860c2
--- /dev/null
+++ b/spec/migrations/migrate_build_stage_reference_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170526185921_migrate_build_stage_reference.rb')
+
+describe MigrateBuildStageReference, :migration do
+ ##
+ # Create test data - pipeline and CI/CD jobs.
+ #
+
+ let(:jobs) { table(:ci_builds) }
+ let(:stages) { table(:ci_stages) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:projects) { table(:projects) }
+
+ before do
+ # Create projects
+ #
+ projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
+ projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2')
+
+ # Create CI/CD pipelines
+ #
+ pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
+ pipelines.create!(id: 2, project_id: 456, ref: 'feature', sha: '21a3deb')
+
+ # Create CI/CD jobs
+ #
+ 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: 456, stage_idx: 2, stage: 'test:2')
+ jobs.create!(id: 6, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
+ jobs.create!(id: 7, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
+ jobs.create!(id: 8, commit_id: 3, project_id: 789, stage_idx: 3, stage: 'deploy')
+
+ # Create CI/CD stages
+ #
+ 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')
+ stages.create(id: 104, pipeline_id: 2, project_id: 456, name: 'test:1')
+ stages.create(id: 105, pipeline_id: 2, project_id: 456, name: 'test:2')
+ stages.create(id: 106, pipeline_id: 2, project_id: 456, name: 'deploy')
+ end
+
+ it 'correctly migrate build stage references' do
+ expect(jobs.where(stage_id: nil).count).to eq 8
+
+ migrate!
+
+ expect(jobs.where(stage_id: nil).count).to eq 1
+
+ expect(jobs.find(1).stage_id).to eq 102
+ expect(jobs.find(2).stage_id).to eq 102
+ expect(jobs.find(3).stage_id).to eq 101
+ expect(jobs.find(4).stage_id).to eq 103
+ expect(jobs.find(5).stage_id).to eq 105
+ expect(jobs.find(6).stage_id).to eq 104
+ expect(jobs.find(7).stage_id).to eq 104
+ expect(jobs.find(8).stage_id).to eq nil
+ end
+end
diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb
new file mode 100644
index 00000000000..c47f2bb8ff9
--- /dev/null
+++ b/spec/migrations/migrate_pipeline_stages_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb')
+
+describe MigratePipelineStages, :migration do
+ ##
+ # Create test data - pipeline and CI/CD jobs.
+ #
+
+ let(:jobs) { table(:ci_builds) }
+ let(:stages) { table(:ci_stages) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:projects) { table(:projects) }
+
+ before do
+ # Create projects
+ #
+ projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
+ projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2')
+
+ # Create CI/CD pipelines
+ #
+ pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
+ pipelines.create!(id: 2, project_id: 456, ref: 'feature', sha: '21a3deb')
+
+ # Create CI/CD jobs
+ #
+ 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: 1, stage: 'test')
+ jobs.create!(id: 5, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy')
+ jobs.create!(id: 6, commit_id: 2, project_id: 456, stage_idx: 3, stage: 'deploy')
+ jobs.create!(id: 7, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2')
+ jobs.create!(id: 8, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
+ jobs.create!(id: 9, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
+ jobs.create!(id: 10, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2')
+ jobs.create!(id: 11, commit_id: 3, project_id: 456, stage_idx: 3, stage: 'deploy')
+ jobs.create!(id: 12, commit_id: 2, project_id: 789, stage_idx: 3, stage: 'deploy')
+ end
+
+ it 'correctly migrates pipeline stages' do
+ expect(stages.count).to be_zero
+
+ migrate!
+
+ expect(stages.count).to eq 6
+ expect(stages.all.pluck(:name))
+ .to match_array %w[test build deploy test:1 test:2 deploy]
+ expect(stages.where(pipeline_id: 1).order(:id).pluck(:name))
+ .to eq %w[test build deploy]
+ expect(stages.where(pipeline_id: 2).order(:id).pluck(:name))
+ .to eq %w[test:1 test:2 deploy]
+ expect(stages.where(pipeline_id: 3).count).to be_zero
+ expect(stages.where(project_id: 789).count).to be_zero
+ end
+end
diff --git a/spec/migrations/move_uploads_to_system_dir_spec.rb b/spec/migrations/move_uploads_to_system_dir_spec.rb
new file mode 100644
index 00000000000..37d66452447
--- /dev/null
+++ b/spec/migrations/move_uploads_to_system_dir_spec.rb
@@ -0,0 +1,68 @@
+require "spec_helper"
+require Rails.root.join("db", "migrate", "20170316163845_move_uploads_to_system_dir.rb")
+
+describe MoveUploadsToSystemDir do
+ let(:migration) { described_class.new }
+ let(:test_dir) { File.join(Rails.root, "tmp", "move_uploads_test") }
+ let(:uploads_dir) { File.join(test_dir, "public", "uploads") }
+ let(:new_uploads_dir) { File.join(uploads_dir, "system") }
+
+ 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(File.join(uploads_dir, 'user'))
+ FileUtils.touch(File.join(uploads_dir, 'user', 'dummy.file'))
+ end
+
+ it 'moves the directory to the new path' do
+ expected_path = File.join(new_uploads_dir, 'user', 'dummy.file')
+
+ migration.up
+
+ expect(File.exist?(expected_path)).to be(true)
+ end
+
+ it 'creates a symlink in the old location' do
+ symlink_path = File.join(uploads_dir, 'user')
+ expected_path = File.join(symlink_path, 'dummy.file')
+
+ migration.up
+
+ expect(File.exist?(expected_path)).to be(true)
+ expect(File.symlink?(symlink_path)).to be(true)
+ end
+ end
+
+ describe "#down" do
+ before do
+ FileUtils.mkdir_p(File.join(new_uploads_dir, 'user'))
+ FileUtils.touch(File.join(new_uploads_dir, 'user', 'dummy.file'))
+ end
+
+ it 'moves the directory to the old path' do
+ expected_path = File.join(uploads_dir, 'user', 'dummy.file')
+
+ migration.down
+
+ expect(File.exist?(expected_path)).to be(true)
+ end
+
+ it 'removes the symlink if it existed' do
+ FileUtils.ln_s(File.join(new_uploads_dir, 'user'), File.join(uploads_dir, 'user'))
+
+ directory = File.join(uploads_dir, 'user')
+ expected_path = File.join(directory, 'dummy.file')
+
+ migration.down
+
+ expect(File.exist?(expected_path)).to be(true)
+ expect(File.symlink?(directory)).to be(false)
+ end
+ end
+end
diff --git a/spec/migrations/rename_more_reserved_project_names_spec.rb b/spec/migrations/rename_more_reserved_project_names_spec.rb
index 36e82729c23..4bd8d4ac0d1 100644
--- a/spec/migrations/rename_more_reserved_project_names_spec.rb
+++ b/spec/migrations/rename_more_reserved_project_names_spec.rb
@@ -17,7 +17,9 @@ describe RenameMoreReservedProjectNames, truncate: true do
describe '#up' do
context 'when project repository exists' do
- before { project.create_repository }
+ before do
+ project.create_repository
+ end
context 'when no exception is raised' do
it 'renames project with reserved names' do
diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb
index 4fb7ed36884..05e021c2e32 100644
--- a/spec/migrations/rename_reserved_project_names_spec.rb
+++ b/spec/migrations/rename_reserved_project_names_spec.rb
@@ -17,7 +17,9 @@ describe RenameReservedProjectNames, truncate: true do
describe '#up' do
context 'when project repository exists' do
- before { project.create_repository }
+ before do
+ project.create_repository
+ end
context 'when no exception is raised' do
it 'renames project with reserved names' do
diff --git a/spec/migrations/rename_system_namespaces_spec.rb b/spec/migrations/rename_system_namespaces_spec.rb
new file mode 100644
index 00000000000..626a6005838
--- /dev/null
+++ b/spec/migrations/rename_system_namespaces_spec.rb
@@ -0,0 +1,254 @@
+require "spec_helper"
+require Rails.root.join("db", "migrate", "20170316163800_rename_system_namespaces.rb")
+
+describe RenameSystemNamespaces, truncate: true do
+ let(:migration) { described_class.new }
+ let(:test_dir) { File.join(Rails.root, "tmp", "tests", "rename_namespaces_test") }
+ let(:uploads_dir) { File.join(test_dir, "public", "uploads") }
+ let(:system_namespace) do
+ namespace = build(:namespace, path: "system")
+ namespace.save(validate: false)
+ namespace
+ end
+
+ def save_invalid_routable(routable)
+ routable.__send__(:prepare_route)
+ routable.save(validate: false)
+ end
+
+ before do
+ FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
+ FileUtils.mkdir_p(uploads_dir)
+ FileUtils.remove_dir(TestEnv.repos_path) if File.directory?(TestEnv.repos_path)
+ allow(migration).to receive(:say)
+ allow(migration).to receive(:uploads_dir).and_return(uploads_dir)
+ end
+
+ describe "#system_namespace" do
+ it "only root namespaces called with path `system`" do
+ system_namespace
+ system_namespace_with_parent = build(:namespace, path: 'system', parent: create(:namespace))
+ system_namespace_with_parent.save(validate: false)
+
+ expect(migration.system_namespace.id).to eq(system_namespace.id)
+ end
+ end
+
+ describe "#up" do
+ before do
+ system_namespace
+ end
+
+ it "doesn't break if there are no namespaces called system" do
+ Namespace.delete_all
+
+ migration.up
+ end
+
+ it "renames namespaces called system" do
+ migration.up
+
+ expect(system_namespace.reload.path).to eq("system0")
+ end
+
+ it "renames the route to the namespace" do
+ migration.up
+
+ expect(system_namespace.reload.full_path).to eq("system0")
+ end
+
+ it "renames the route for projects of the namespace" do
+ project = build(:project, path: "project-path", namespace: system_namespace)
+ save_invalid_routable(project)
+
+ migration.up
+
+ expect(project.route.reload.path).to eq("system0/project-path")
+ end
+
+ it "doesn't touch routes of namespaces that look like system" do
+ namespace = create(:group, path: 'systemlookalike')
+ project = create(:project, namespace: namespace, path: 'the-project')
+
+ migration.up
+
+ expect(project.route.reload.path).to eq('systemlookalike/the-project')
+ expect(namespace.route.reload.path).to eq('systemlookalike')
+ end
+
+ it "moves the the repository for a project in the namespace" do
+ project = build(:project, namespace: system_namespace, path: "system-project")
+ save_invalid_routable(project)
+ TestEnv.copy_repo(project,
+ bare_repo: TestEnv.factory_repo_path_bare,
+ refs: TestEnv::BRANCH_SHA)
+ expected_repo = File.join(TestEnv.repos_path, "system0", "system-project.git")
+
+ migration.up
+
+ expect(File.directory?(expected_repo)).to be(true)
+ end
+
+ it "moves the uploads for the namespace" do
+ allow(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0")
+ expect(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0")
+
+ migration.up
+ end
+
+ it "moves the pages for the namespace" do
+ allow(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0")
+ expect(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0")
+
+ migration.up
+ end
+
+ describe "clears the markdown cache for projects in the system namespace" do
+ let!(:project) do
+ project = build(:project, namespace: system_namespace)
+ save_invalid_routable(project)
+ project
+ end
+
+ it 'removes description_html from projects' do
+ migration.up
+
+ expect(project.reload.description_html).to be_nil
+ end
+
+ it 'removes issue descriptions' do
+ issue = create(:issue, project: project, description_html: 'Issue description')
+
+ migration.up
+
+ expect(issue.reload.description_html).to be_nil
+ end
+
+ it 'removes merge request descriptions' do
+ merge_request = create(:merge_request,
+ source_project: project,
+ target_project: project,
+ description_html: 'MergeRequest description')
+
+ migration.up
+
+ expect(merge_request.reload.description_html).to be_nil
+ end
+
+ it 'removes note html' do
+ note = create(:note,
+ project: project,
+ noteable: create(:issue, project: project),
+ note_html: 'note description')
+
+ migration.up
+
+ expect(note.reload.note_html).to be_nil
+ end
+
+ it 'removes milestone description' do
+ milestone = create(:milestone,
+ project: project,
+ description_html: 'milestone description')
+
+ migration.up
+
+ expect(milestone.reload.description_html).to be_nil
+ end
+ end
+
+ context "system namespace -> subgroup -> system0 project" do
+ it "updates the route of the project correctly" do
+ subgroup = build(:group, path: "subgroup", parent: system_namespace)
+ save_invalid_routable(subgroup)
+ project = build(:project, path: "system0", namespace: subgroup)
+ save_invalid_routable(project)
+
+ migration.up
+
+ expect(project.route.reload.path).to eq("system0/subgroup/system0")
+ end
+ end
+ end
+
+ describe "#move_repositories" do
+ let(:namespace) { create(:group, name: "hello-group") }
+ it "moves a project for a namespace" do
+ create(:project, namespace: namespace, path: "hello-project")
+ expected_path = File.join(TestEnv.repos_path, "bye-group", "hello-project.git")
+
+ migration.move_repositories(namespace, "hello-group", "bye-group")
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+
+ it "moves a namespace in a subdirectory correctly" do
+ child_namespace = create(:group, name: "sub-group", parent: namespace)
+ create(:project, namespace: child_namespace, path: "hello-project")
+
+ expected_path = File.join(TestEnv.repos_path, "hello-group", "renamed-sub-group", "hello-project.git")
+
+ migration.move_repositories(child_namespace, "hello-group/sub-group", "hello-group/renamed-sub-group")
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+
+ it "moves a parent namespace with subdirectories" do
+ child_namespace = create(:group, name: "sub-group", parent: namespace)
+ create(:project, namespace: child_namespace, path: "hello-project")
+ expected_path = File.join(TestEnv.repos_path, "renamed-group", "sub-group", "hello-project.git")
+
+ migration.move_repositories(child_namespace, "hello-group", "renamed-group")
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+ end
+
+ describe "#move_namespace_folders" do
+ it "moves a namespace with files" do
+ source = File.join(uploads_dir, "parent-group", "sub-group")
+ FileUtils.mkdir_p(source)
+ destination = File.join(uploads_dir, "parent-group", "moved-group")
+ FileUtils.touch(File.join(source, "test.txt"))
+ expected_file = File.join(destination, "test.txt")
+
+ migration.move_namespace_folders(uploads_dir, File.join("parent-group", "sub-group"), File.join("parent-group", "moved-group"))
+
+ expect(File.exist?(expected_file)).to be(true)
+ end
+
+ it "moves a parent namespace uploads" do
+ source = File.join(uploads_dir, "parent-group", "sub-group")
+ FileUtils.mkdir_p(source)
+ destination = File.join(uploads_dir, "moved-parent", "sub-group")
+ FileUtils.touch(File.join(source, "test.txt"))
+ expected_file = File.join(destination, "test.txt")
+
+ migration.move_namespace_folders(uploads_dir, "parent-group", "moved-parent")
+
+ expect(File.exist?(expected_file)).to be(true)
+ end
+ end
+
+ describe "#child_ids_for_parent" do
+ it "collects child ids for all levels" do
+ parent = create(:group)
+ first_child = create(:group, parent: parent)
+ second_child = create(:group, parent: parent)
+ third_child = create(:group, parent: second_child)
+ all_ids = [parent.id, first_child.id, second_child.id, third_child.id]
+
+ collected_ids = migration.child_ids_for_parent(parent, ids: [parent.id])
+
+ expect(collected_ids).to contain_exactly(*all_ids)
+ end
+ end
+
+ describe "#remove_last_ocurrence" do
+ it "removes only the last occurance of a string" do
+ input = "this/is/system/namespace/with/system"
+
+ expect(migration.remove_last_occurrence(input, "system")).to eq("this/is/system/namespace/with/")
+ end
+ end
+end
diff --git a/spec/migrations/update_upload_paths_to_system_spec.rb b/spec/migrations/update_upload_paths_to_system_spec.rb
new file mode 100644
index 00000000000..7df44515424
--- /dev/null
+++ b/spec/migrations/update_upload_paths_to_system_spec.rb
@@ -0,0 +1,53 @@
+require "spec_helper"
+require Rails.root.join("db", "post_migrate", "20170317162059_update_upload_paths_to_system.rb")
+
+describe UpdateUploadPathsToSystem do
+ let(:migration) { described_class.new }
+
+ before do
+ allow(migration).to receive(:say)
+ end
+
+ describe "#uploads_to_switch_to_new_path" do
+ it "contains only uploads with the old path for the correct models" do
+ _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg")
+ _upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg")
+ _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg")
+ old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg")
+ group_upload = create(:upload, model: create(:group), path: "uploads/group/avatar.jpg")
+
+ expect(Upload.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload)
+ end
+ end
+
+ describe "#uploads_to_switch_to_old_path" do
+ it "contains only uploads with the new path for the correct models" do
+ _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg")
+ upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg")
+ _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg")
+ _old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg")
+
+ expect(Upload.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path)
+ end
+ end
+
+ describe "#up", truncate: true do
+ it "updates old upload records to the new path" do
+ old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg")
+
+ migration.up
+
+ expect(old_upload.reload.path).to eq("uploads/system/project/avatar.jpg")
+ end
+ end
+
+ describe "#down", truncate: true do
+ it "updates the new system patsh to the old paths" do
+ new_upload = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg")
+
+ migration.down
+
+ expect(new_upload.reload.path).to eq("uploads/project/avatar.jpg")
+ end
+ end
+end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index fa229542f70..166a4474abf 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -78,7 +78,9 @@ describe ApplicationSetting, models: true do
# Upgraded databases will have this sort of content
context 'repository_storages is a String, not an Array' do
- before { setting.__send__(:raw_write_attribute, :repository_storages, 'default') }
+ before do
+ setting.__send__(:raw_write_attribute, :repository_storages, 'default')
+ end
it { expect(setting.repository_storages_before_type_cast).to eq('default') }
it { expect(setting.repository_storages).to eq(['default']) }
diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb
index f19e1af65a6..e1193e0d19a 100644
--- a/spec/models/blob_spec.rb
+++ b/spec/models/blob_spec.rb
@@ -199,6 +199,14 @@ describe Blob do
end
end
+ describe '#file_type' do
+ it 'returns the file type' do
+ blob = fake_blob(path: 'README.md')
+
+ expect(blob.file_type).to eq(:readme)
+ end
+ end
+
describe '#simple_viewer' do
context 'when the blob is empty' do
it 'returns an empty viewer' do
diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb
index d56379eb59d..574438838d8 100644
--- a/spec/models/blob_viewer/base_spec.rb
+++ b/spec/models/blob_viewer/base_spec.rb
@@ -106,9 +106,9 @@ describe BlobViewer::Base, model: true do
end
describe '#render_error' do
- context 'when expanded' do
+ context 'when the blob is expanded' do
before do
- viewer.expanded = true
+ blob.expand!
end
context 'when the blob size is larger than the size limit' do
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 219db365a91..333f4139a96 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -21,22 +21,29 @@ describe BroadcastMessage, models: true do
end
describe '.current' do
- it "returns last message if time match" do
+ it 'returns message if time match' do
message = create(:broadcast_message)
- expect(BroadcastMessage.current).to eq message
+ expect(BroadcastMessage.current).to include(message)
end
- it "returns nil if time not come" do
+ it 'returns multiple messages if time match' do
+ message1 = create(:broadcast_message)
+ message2 = create(:broadcast_message)
+
+ expect(BroadcastMessage.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_nil
+ expect(BroadcastMessage.current).to be_empty
end
- it "returns nil if time has passed" do
+ it 'returns empty list if time has passed' do
create(:broadcast_message, :expired)
- expect(BroadcastMessage.current).to be_nil
+ expect(BroadcastMessage.current).to be_empty
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index b0716e04d3d..3816422fec6 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -21,6 +21,18 @@ describe Ci::Build, :models do
it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) }
+ describe '.manual_actions' do
+ let!(:manual_but_created) { create(:ci_build, :manual, status: :created, pipeline: pipeline) }
+ let!(:manual_but_succeeded) { create(:ci_build, :manual, status: :success, pipeline: pipeline) }
+ let!(:manual_action) { create(:ci_build, :manual, pipeline: pipeline) }
+
+ subject { described_class.manual_actions }
+
+ it { is_expected.to include(manual_action) }
+ it { is_expected.to include(manual_but_succeeded) }
+ it { is_expected.not_to include(manual_but_created) }
+ end
+
describe '#actionize' do
context 'when build is a created' do
before do
@@ -95,12 +107,18 @@ describe Ci::Build, :models do
it { is_expected.to be_truthy }
context 'is expired' do
- before { build.update(artifacts_expire_at: Time.now - 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now - 7.days)
+ end
+
it { is_expected.to be_falsy }
end
context 'is not expired' do
- before { build.update(artifacts_expire_at: Time.now + 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now + 7.days)
+ end
+
it { is_expected.to be_truthy }
end
end
@@ -110,13 +128,17 @@ describe Ci::Build, :models do
subject { build.artifacts_expired? }
context 'is expired' do
- before { build.update(artifacts_expire_at: Time.now - 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now - 7.days)
+ end
it { is_expected.to be_truthy }
end
context 'is not expired' do
- before { build.update(artifacts_expire_at: Time.now + 7.days) }
+ before do
+ build.update(artifacts_expire_at: Time.now + 7.days)
+ end
it { is_expected.to be_falsey }
end
@@ -141,7 +163,9 @@ describe Ci::Build, :models do
context 'when artifacts_expire_at is specified' do
let(:expire_at) { Time.now + 7.days }
- before { build.artifacts_expire_at = expire_at }
+ before do
+ build.artifacts_expire_at = expire_at
+ end
it { is_expected.to be_within(5).of(expire_at - Time.now) }
end
@@ -926,6 +950,10 @@ describe Ci::Build, :models do
context 'when other build is retried' do
let!(:retried_build) { Ci::Build.retry(other_build, user) }
+ before do
+ retried_build.success
+ end
+
it 'returns a retried build' do
is_expected.to contain_exactly(retried_build)
end
@@ -1071,7 +1099,9 @@ describe Ci::Build, :models do
describe '#has_expiring_artifacts?' do
context 'when artifacts have expiration date set' do
- before { build.update(artifacts_expire_at: 1.day.from_now) }
+ before do
+ build.update(artifacts_expire_at: 1.day.from_now)
+ end
it 'has expiring artifacts' do
expect(build).to have_expiring_artifacts
@@ -1079,7 +1109,9 @@ describe Ci::Build, :models do
end
context 'when artifacts do not have expiration date set' do
- before { build.update(artifacts_expire_at: nil) }
+ before do
+ build.update(artifacts_expire_at: nil)
+ end
it 'does not have expiring artifacts' do
expect(build).not_to have_expiring_artifacts
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb
index 8f6ab908987..d43c33d3807 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/legacy_stage_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Stage, models: true do
+describe Ci::LegacyStage, :models do
let(:stage) { build(:ci_stage) }
let(:pipeline) { stage.pipeline }
let(:stage_name) { stage.name }
@@ -55,6 +55,17 @@ describe Ci::Stage, models: true do
expect(stage.groups.map(&:name))
.to eq %w[aaaaa rspec spinach]
end
+
+ context 'when a name is nil on legacy pipelines' do
+ before do
+ pipeline.builds.first.update_attribute(:name, nil)
+ end
+
+ it 'returns an array of three groups' do
+ expect(stage.groups.map(&:name))
+ .to eq ['', 'aaaaa', 'rspec', 'spinach']
+ end
+ end
end
describe '#statuses_count' do
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index ae1b01b76ab..e86cbe8498a 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -224,8 +224,19 @@ describe Ci::Pipeline, models: true do
status: 'success')
end
- describe '#stages' do
- subject { pipeline.stages }
+ describe '#stage_seeds' do
+ let(:pipeline) do
+ create(:ci_pipeline, config: { rspec: { script: 'rake' } })
+ end
+
+ it 'returns preseeded stage seeds object' do
+ expect(pipeline.stage_seeds).to all(be_a Gitlab::Ci::Stage::Seed)
+ expect(pipeline.stage_seeds.count).to eq 1
+ end
+ end
+
+ describe '#legacy_stages' do
+ subject { pipeline.legacy_stages }
context 'stages list' do
it 'returns ordered list of stages' do
@@ -274,7 +285,7 @@ describe Ci::Pipeline, models: true do
end
it 'populates stage with correct number of warnings' do
- deploy_stage = pipeline.stages.third
+ deploy_stage = pipeline.legacy_stages.third
expect(deploy_stage).not_to receive(:statuses)
expect(deploy_stage).to have_warnings
@@ -288,22 +299,22 @@ describe Ci::Pipeline, models: true do
end
end
- describe '#stages_name' do
+ describe '#stages_names' do
it 'returns a valid names of stages' do
- expect(pipeline.stages_name).to eq(%w(build test deploy))
+ expect(pipeline.stages_names).to eq(%w(build test deploy))
end
end
end
- describe '#stage' do
- subject { pipeline.stage('test') }
+ describe '#legacy_stage' do
+ subject { pipeline.legacy_stage('test') }
context 'with status in stage' do
before do
create(:commit_status, pipeline: pipeline, stage: 'test')
end
- it { expect(subject).to be_a Ci::Stage }
+ it { expect(subject).to be_a Ci::LegacyStage }
it { expect(subject.name).to eq 'test' }
it { expect(subject.statuses).not_to be_empty }
end
@@ -524,6 +535,20 @@ describe Ci::Pipeline, models: true do
end
end
+ describe '#has_stage_seeds?' do
+ context 'when pipeline has stage seeds' do
+ subject { build(:ci_pipeline_with_one_job) }
+
+ it { is_expected.to have_stage_seeds }
+ end
+
+ context 'when pipeline does not have stage seeds' do
+ subject { create(:ci_pipeline_without_jobs) }
+
+ it { is_expected.not_to have_stage_seeds }
+ end
+ end
+
describe '#has_warnings?' do
subject { pipeline.has_warnings? }
@@ -1131,7 +1156,9 @@ describe Ci::Pipeline, models: true do
end
context 'when pipeline is not stuck' do
- before { create(:ci_runner, :shared, :online) }
+ before do
+ create(:ci_runner, :shared, :online)
+ end
it 'is not stuck' do
expect(pipeline).not_to be_stuck
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 72f83d63224..6056d78da4e 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -20,8 +20,8 @@ describe Commit, models: true do
end
it 'caches the author' do
+ allow(RequestStore).to receive(:active?).and_return(true)
user = create(:user, email: commit.author_email)
- expect(RequestStore).to receive(:active?).twice.and_return(true)
expect_any_instance_of(Commit).to receive(:find_author_by_any_email).and_call_original
expect(commit.author).to eq(user)
@@ -67,11 +67,11 @@ describe Commit, models: true do
expect(commit.title).to eq("--no commit message")
end
- it "truncates a message without a newline at 80 characters" do
+ it 'truncates a message without a newline at natural break to 80 characters' do
message = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit. Vivamus egestas lacinia lacus, sed rutrum mauris.'
allow(commit).to receive(:safe_message).and_return(message)
- expect(commit.title).to eq("#{message[0..79]}…")
+ expect(commit.title).to eq('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis…')
end
it "truncates a message with a newline before 80 characters at the newline" do
@@ -113,6 +113,28 @@ eos
end
end
+ describe 'description' do
+ it 'returns description of commit message if title less than 100 characters' do
+ message = <<eos
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit.
+Vivamus egestas lacinia lacus, sed rutrum mauris.
+eos
+
+ allow(commit).to receive(:safe_message).and_return(message)
+ expect(commit.description).to eq('Vivamus egestas lacinia lacus, sed rutrum mauris.')
+ end
+
+ it 'returns full commit message if commit title more than 100 characters' do
+ message = <<eos
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sodales id felis id blandit. Vivamus egestas lacinia lacus, sed rutrum mauris.
+Vivamus egestas lacinia lacus, sed rutrum mauris.
+eos
+
+ allow(commit).to receive(:safe_message).and_return(message)
+ expect(commit.description).to eq(message)
+ end
+ end
+
describe "delegation" do
subject { commit }
@@ -184,19 +206,25 @@ eos
it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy }
context 'commit has no description' do
- before { allow(commit).to receive(:description?).and_return(false) }
+ before do
+ allow(commit).to receive(:description?).and_return(false)
+ end
it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy }
end
context "another_commit's description does not revert commit" do
- before { allow(commit).to receive(:description).and_return("Foo Bar") }
+ before do
+ allow(commit).to receive(:description).and_return("Foo Bar")
+ end
it { expect(commit.reverts_commit?(another_commit, user)).to be_falsy }
end
context "another_commit's description reverts commit" do
- before { allow(commit).to receive(:description).and_return("Foo #{another_commit.revert_description} Bar") }
+ before do
+ allow(commit).to receive(:description).and_return("Foo #{another_commit.revert_description} Bar")
+ end
it { expect(commit.reverts_commit?(another_commit, user)).to be_truthy }
end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index c50b8bf7b13..9262ce08987 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -31,7 +31,10 @@ describe CommitStatus, :models do
describe '#author' do
subject { commit_status.author }
- before { commit_status.author = User.new }
+
+ before do
+ commit_status.author = User.new
+ end
it { is_expected.to eq(commit_status.user) }
end
@@ -50,14 +53,18 @@ describe CommitStatus, :models do
subject { commit_status.started? }
context 'without started_at' do
- before { commit_status.started_at = nil }
+ before do
+ commit_status.started_at = nil
+ end
it { is_expected.to be_falsey }
end
%w[running success failed].each do |status|
context "if commit status is #{status}" do
- before { commit_status.status = status }
+ before do
+ commit_status.status = status
+ end
it { is_expected.to be_truthy }
end
@@ -65,7 +72,9 @@ describe CommitStatus, :models do
%w[pending canceled].each do |status|
context "if commit status is #{status}" do
- before { commit_status.status = status }
+ before do
+ commit_status.status = status
+ end
it { is_expected.to be_falsey }
end
@@ -77,7 +86,9 @@ describe CommitStatus, :models do
%w[pending running].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_truthy }
end
@@ -85,7 +96,9 @@ describe CommitStatus, :models do
%w[success failed canceled].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_falsey }
end
@@ -97,7 +110,9 @@ describe CommitStatus, :models do
%w[success failed canceled].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_truthy }
end
@@ -105,7 +120,9 @@ describe CommitStatus, :models do
%w[pending running].each do |state|
context "if commit_status.status is #{state}" do
- before { commit_status.status = state }
+ before do
+ commit_status.status = state
+ end
it { is_expected.to be_falsey }
end
@@ -271,7 +288,9 @@ describe CommitStatus, :models do
subject { commit_status.before_sha }
context 'when no before_sha is set for pipeline' do
- before { pipeline.before_sha = nil }
+ before do
+ pipeline.before_sha = nil
+ end
it 'returns blank sha' do
is_expected.to eq(Gitlab::Git::BLANK_SHA)
@@ -280,7 +299,10 @@ describe CommitStatus, :models do
context 'for before_sha set for pipeline' do
let(:value) { '1234' }
- before { pipeline.before_sha = value }
+
+ before do
+ pipeline.before_sha = value
+ end
it 'returns the set value' do
is_expected.to eq(value)
diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb
index 4829ef17a20..97b7e48bb3c 100644
--- a/spec/models/concerns/access_requestable_spec.rb
+++ b/spec/models/concerns/access_requestable_spec.rb
@@ -14,7 +14,9 @@ describe AccessRequestable do
let(:group) { create(:group, :public, :access_requestable) }
let(:user) { create(:user) }
- before { group.request_access(user) }
+ before do
+ group.request_access(user)
+ end
it { expect(group.requesters.exists?(user_id: user)).to be_truthy }
end
@@ -32,7 +34,9 @@ describe AccessRequestable do
let(:project) { create(:empty_project, :public, :access_requestable) }
let(:user) { create(:user) }
- before { project.request_access(user) }
+ before do
+ project.request_access(user)
+ end
it { expect(project.requesters.exists?(user_id: user)).to be_truthy }
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 27890e33b49..1a9bda64191 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -200,7 +200,9 @@ describe Issuable do
let(:project) { issue.project }
context 'user is not a participant in the issue' do
- before { allow(issue).to receive(:participants).with(user).and_return([]) }
+ before do
+ allow(issue).to receive(:participants).with(user).and_return([])
+ end
it 'returns false when no subcription exists' do
expect(issue.subscribed?(user, project)).to be_falsey
@@ -220,7 +222,9 @@ describe Issuable do
end
context 'user is a participant in the issue' do
- before { allow(issue).to receive(:participants).with(user).and_return([user]) }
+ before do
+ allow(issue).to receive(:participants).with(user).and_return([user])
+ end
it 'returns false when no subcription exists' do
expect(issue.subscribed?(user, project)).to be_truthy
@@ -252,7 +256,9 @@ describe Issuable do
end
context "issue is assigned" do
- before { issue.assignees << user }
+ before do
+ issue.assignees << user
+ end
it "returns correct hook data" do
expect(data[:assignees].first).to eq(user.hook_attrs)
@@ -276,7 +282,9 @@ describe Issuable do
context 'issue has labels' do
let(:labels) { [create(:label), create(:label)] }
- before { issue.update_attribute(:labels, labels)}
+ before do
+ issue.update_attribute(:labels, labels)
+ end
it 'includes labels in the hook data' do
expect(data[:labels]).to eq(labels.map(&:hook_attrs))
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index e382c7120de..e2a29e0ae70 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -61,7 +61,9 @@ describe Issue, "Mentionable" do
end
context 'when the current user can see the issue' do
- before { private_project.team << [user, Gitlab::Access::DEVELOPER] }
+ before do
+ private_project.team << [user, Gitlab::Access::DEVELOPER]
+ end
it 'includes the reference' do
expect(referenced_issues(user)).to contain_exactly(private_issue, public_issue)
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index a0765a264cf..808247ebfd5 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -40,7 +40,10 @@ describe ReactiveCaching, caching: true do
let(:instance) { CacheTest.new(666, &calculation) }
describe '#with_reactive_cache' do
- before { stub_reactive_cache }
+ before do
+ stub_reactive_cache
+ end
+
subject(:go!) { instance.result }
context 'when cache is empty' do
@@ -60,12 +63,17 @@ describe ReactiveCaching, caching: true do
end
context 'when the cache is full' do
- before { stub_reactive_cache(instance, 4) }
+ before do
+ stub_reactive_cache(instance, 4)
+ end
it { is_expected.to eq(2) }
context 'and expired' do
- before { invalidate_reactive_cache(instance) }
+ before do
+ invalidate_reactive_cache(instance)
+ end
+
it { is_expected.to be_nil }
end
end
@@ -84,7 +92,9 @@ describe ReactiveCaching, caching: true do
subject(:go!) { instance.exclusively_update_reactive_cache! }
context 'when the lease is free and lifetime is not exceeded' do
- before { stub_reactive_cache(instance, "preexisting") }
+ before do
+ stub_reactive_cache(instance, "preexisting")
+ end
it 'takes and releases the lease' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000")
@@ -106,7 +116,10 @@ describe ReactiveCaching, caching: true do
end
context 'and #calculate_reactive_cache raises an exception' do
- before { stub_reactive_cache(instance, "preexisting") }
+ before do
+ stub_reactive_cache(instance, "preexisting")
+ end
+
let(:calculation) { -> { raise "foo"} }
it 'leaves the cache untouched' do
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 0e10d91836d..65f05121b40 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -122,16 +122,7 @@ describe Group, 'Routable' do
it { expect(group.full_path).to eq(group.path) }
it { expect(nested_group.full_path).to eq("#{group.full_path}/#{nested_group.path}") }
- context 'with RequestStore active' do
- before do
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
- end
-
+ context 'with RequestStore active', :request_store do
it 'does not load the route table more than once' do
expect(group).to receive(:uncached_full_path).once.and_call_original
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index 4b0bfa43abf..882afeccfc6 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -49,7 +49,10 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
end
context 'token is generated' do
- before { subject.send("reset_#{token_field}!") }
+ before do
+ subject.send("reset_#{token_field}!")
+ end
+
it 'persists a new token' do
expect(subject.send(:read_attribute, token_field)).to be_a String
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index d15ff9e5ffd..eba0175c54c 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -131,7 +131,7 @@ describe Deployment, models: true do
end
context 'with other actions' do
- let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
+ let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
context 'when matching action is defined' do
let(:deployment) { FactoryGirl.build(:deployment, deployable: build, on_stop: 'close_other_app') }
@@ -159,7 +159,7 @@ describe Deployment, models: true do
context 'when matching action is defined' do
let(:build) { create(:ci_build) }
let(:deployment) { FactoryGirl.build(:deployment, deployable: build, on_stop: 'close_app') }
- let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
+ let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
it { is_expected.to be_truthy }
end
diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb
new file mode 100644
index 00000000000..3755f4a56f3
--- /dev/null
+++ b/spec/models/diff_viewer/base_spec.rb
@@ -0,0 +1,150 @@
+require 'spec_helper'
+
+describe DiffViewer::Base, model: true do
+ include FakeBlobHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
+
+ let(:viewer_class) do
+ Class.new(described_class) do
+ include DiffViewer::ServerSide
+
+ self.extensions = %w(jpg)
+ self.binary = true
+ self.collapse_limit = 1.megabyte
+ self.size_limit = 5.megabytes
+ end
+ end
+
+ let(:viewer) { viewer_class.new(diff_file) }
+
+ describe '.can_render?' do
+ context 'when the extension is supported' do
+ let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
+
+ context 'when the binaryness matches' do
+ it 'returns true' do
+ expect(viewer_class.can_render?(diff_file)).to be_truthy
+ end
+ end
+
+ context 'when the binaryness does not match' do
+ before do
+ allow(diff_file.old_blob).to receive(:binary?).and_return(false)
+ allow(diff_file.new_blob).to receive(:binary?).and_return(false)
+ end
+
+ it 'returns false' do
+ expect(viewer_class.can_render?(diff_file)).to be_falsey
+ end
+ end
+ end
+
+ context 'when the file type is supported' do
+ let(:commit) { project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('LICENSE') }
+
+ before do
+ viewer_class.file_types = %i(license)
+ viewer_class.binary = false
+ end
+
+ context 'when the binaryness matches' do
+ it 'returns true' do
+ expect(viewer_class.can_render?(diff_file)).to be_truthy
+ end
+ end
+
+ context 'when the binaryness does not match' do
+ before do
+ allow(diff_file.old_blob).to receive(:binary?).and_return(true)
+ allow(diff_file.new_blob).to receive(:binary?).and_return(true)
+ end
+
+ it 'returns false' do
+ expect(viewer_class.can_render?(diff_file)).to be_falsey
+ end
+ end
+ end
+
+ context 'when the extension and file type are not supported' do
+ it 'returns false' do
+ expect(viewer_class.can_render?(diff_file)).to be_falsey
+ end
+ end
+
+ context 'when the file was renamed and only the old blob is supported' do
+ let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
+
+ before do
+ allow(diff_file).to receive(:renamed_file?).and_return(true)
+ allow(diff_file.new_blob).to receive(:extension).and_return('jpeg')
+ end
+
+ it 'returns false' do
+ expect(viewer_class.can_render?(diff_file)).to be_falsey
+ end
+ end
+ end
+
+ describe '#collapsed?' do
+ context 'when the combined blob size is larger than the collapse limit' do
+ before do
+ allow(diff_file.old_blob).to receive(:raw_size).and_return(512.kilobytes)
+ allow(diff_file.new_blob).to receive(:raw_size).and_return(513.kilobytes)
+ end
+
+ it 'returns true' do
+ expect(viewer.collapsed?).to be_truthy
+ end
+ end
+
+ context 'when the combined blob size is smaller than the collapse limit' do
+ it 'returns false' do
+ expect(viewer.collapsed?).to be_falsey
+ end
+ end
+ end
+
+ describe '#too_large?' do
+ context 'when the combined blob size is larger than the size limit' do
+ before do
+ allow(diff_file.old_blob).to receive(:raw_size).and_return(2.megabytes)
+ allow(diff_file.new_blob).to receive(:raw_size).and_return(4.megabytes)
+ end
+
+ it 'returns true' do
+ expect(viewer.too_large?).to be_truthy
+ end
+ end
+
+ context 'when the blob size is smaller than the size limit' do
+ it 'returns false' do
+ expect(viewer.too_large?).to be_falsey
+ end
+ end
+ end
+
+ describe '#render_error' do
+ context 'when the combined blob size is larger than the size limit' do
+ before do
+ allow(diff_file.old_blob).to receive(:raw_size).and_return(2.megabytes)
+ allow(diff_file.new_blob).to receive(:raw_size).and_return(4.megabytes)
+ end
+
+ it 'returns :too_large' do
+ expect(viewer.render_error).to eq(:too_large)
+ end
+ end
+
+ context 'when the combined blob size is smaller than the size limit' do
+ it 'returns nil' do
+ expect(viewer.render_error).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb
new file mode 100644
index 00000000000..2d926e06936
--- /dev/null
+++ b/spec/models/diff_viewer/server_side_spec.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+
+describe DiffViewer::ServerSide, model: true 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') }
+
+ let(:viewer_class) do
+ Class.new(DiffViewer::Base) do
+ include DiffViewer::ServerSide
+ end
+ end
+
+ subject { viewer_class.new(diff_file) }
+
+ describe '#prepare!' do
+ it 'loads all diff file data' do
+ expect(diff_file.old_blob).to receive(:load_all_data!)
+ expect(diff_file.new_blob).to receive(:load_all_data!)
+
+ subject.prepare!
+ end
+ end
+
+ describe '#render_error' do
+ context 'when the diff file is stored externally' do
+ before do
+ allow(diff_file).to receive(:stored_externally?).and_return(true)
+ end
+
+ it 'return :server_side_but_stored_externally' do
+ expect(subject.render_error).to eq(:server_side_but_stored_externally)
+ end
+ end
+ end
+end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index f711065a0ab..f36c165ef7d 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -170,7 +170,7 @@ describe Environment, models: true do
context 'when matching action is defined' do
let(:build) { create(:ci_build) }
let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') }
- let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
+ let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
context 'when environment is available' do
before do
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index f4c3e6d503f..152e97e09bf 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -19,7 +19,10 @@ describe GenericCommitStatus, models: true do
describe '#context' do
subject { generic_commit_status.context }
- before { generic_commit_status.context = 'my_context' }
+
+ before do
+ generic_commit_status.context = 'my_context'
+ end
it { is_expected.to eq(generic_commit_status.name) }
end
@@ -39,7 +42,9 @@ describe GenericCommitStatus, models: true do
end
context 'when user has ability to see datails' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'details path points to an external URL' do
expect(status).to have_details
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 316bf153660..449b7c2f7d7 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -143,14 +143,20 @@ describe Group, models: true do
describe '#add_user' do
let(:user) { create(:user) }
- before { group.add_user(user, GroupMember::MASTER) }
+
+ before do
+ group.add_user(user, GroupMember::MASTER)
+ end
it { expect(group.group_members.masters.map(&:user)).to include(user) }
end
describe '#add_users' do
let(:user) { create(:user) }
- before { group.add_users([user.id], GroupMember::GUEST) }
+
+ before do
+ group.add_users([user.id], GroupMember::GUEST)
+ end
it "updates the group permission" do
expect(group.group_members.guests.map(&:user)).to include(user)
@@ -162,7 +168,10 @@ describe Group, models: true do
describe '#avatar_type' do
let(:user) { create(:user) }
- before { group.add_user(user, GroupMember::MASTER) }
+
+ before do
+ group.add_user(user, GroupMember::MASTER)
+ end
it "is true if avatar is image" do
group.update_attribute(:avatar, 'uploads/avatar.png')
@@ -179,10 +188,12 @@ 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/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 { group.add_master(user) }
+ before do
+ group.add_master(user)
+ end
it 'shows correct avatar url' do
expect(group.avatar_url).to eq(avatar_path)
@@ -222,7 +233,9 @@ describe Group, models: true do
end
describe '#has_owner?' do
- before { @members = setup_group_members(group) }
+ before do
+ @members = setup_group_members(group)
+ end
it { expect(group.has_owner?(@members[:owner])).to be_truthy }
it { expect(group.has_owner?(@members[:master])).to be_falsey }
@@ -233,7 +246,9 @@ describe Group, models: true do
end
describe '#has_master?' do
- before { @members = setup_group_members(group) }
+ before do
+ @members = setup_group_members(group)
+ end
it { expect(group.has_master?(@members[:owner])).to be_falsey }
it { expect(group.has_master?(@members[:master])).to be_truthy }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index bb4e70db2e9..12e7d646382 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -245,7 +245,9 @@ describe Issue, models: true do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
it { is_expected.to eq true }
@@ -259,12 +261,18 @@ describe Issue, models: true do
let(:to_project) { create(:empty_project) }
context 'destination project allowed' do
- before { to_project.team << [user, :reporter] }
+ before do
+ to_project.team << [user, :reporter]
+ end
+
it { is_expected.to eq true }
end
context 'destination project not allowed' do
- before { to_project.team << [user, :guest] }
+ before do
+ to_project.team << [user, :guest]
+ end
+
it { is_expected.to eq false }
end
end
@@ -549,7 +557,9 @@ describe Issue, models: true do
end
context 'when the user is the project owner' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'returns true for a regular issue' do
issue = build(:issue, project: project)
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index ed9fde57bf7..25f7062860b 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -36,7 +36,9 @@ describe MergeRequestDiff, models: true do
end
context 'when the raw diffs are empty' do
- before { mr_diff.update_attributes(st_diffs: '') }
+ before do
+ mr_diff.update_attributes(st_diffs: '')
+ end
it 'returns an empty DiffCollection' do
expect(mr_diff.raw_diffs).to be_a(Gitlab::Git::DiffCollection)
@@ -45,7 +47,9 @@ describe MergeRequestDiff, models: true do
end
context 'when the raw diffs have invalid content' do
- before { mr_diff.update_attributes(st_diffs: ["--broken-diff"]) }
+ before do
+ mr_diff.update_attributes(st_diffs: ["--broken-diff"])
+ end
it 'returns an empty DiffCollection' do
expect(mr_diff.raw_diffs.to_a).to be_empty
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 060754fab63..cd2f11dec96 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -892,7 +892,9 @@ describe MergeRequest, models: true do
end
context 'when broken' do
- before { allow(subject).to receive(:broken?) { true } }
+ before do
+ allow(subject).to receive(:broken?) { true }
+ end
it 'becomes unmergeable' do
expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged')
@@ -944,7 +946,9 @@ describe MergeRequest, models: true do
end
context 'when not open' do
- before { subject.close }
+ before do
+ subject.close
+ end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
@@ -952,7 +956,9 @@ describe MergeRequest, models: true do
end
context 'when working in progress' do
- before { subject.title = 'WIP MR' }
+ before do
+ subject.title = 'WIP MR'
+ end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
@@ -960,7 +966,9 @@ describe MergeRequest, models: true do
end
context 'when broken' do
- before { allow(subject).to receive(:broken?) { true } }
+ before do
+ allow(subject).to receive(:broken?) { true }
+ end
it 'returns false' do
expect(subject.mergeable_state?).to be_falsey
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 0e74f1ab1bd..145c7ad5770 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -43,6 +43,12 @@ describe Namespace, models: true do
end
end
+ context "is case insensitive" do
+ let(:group) { build(:group, path: "System") }
+
+ it { expect(group).not_to be_valid }
+ end
+
context 'top-level group' do
let(:group) { build(:group, path: 'tree') }
@@ -178,8 +184,8 @@ describe Namespace, models: true do
let(:parent) { create(:group, name: 'parent', path: 'parent') }
let(:child) { create(:group, name: 'child', path: 'child', parent: parent) }
let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child) }
- let(:uploads_dir) { File.join(CarrierWave.root, 'uploads') }
- let(:pages_dir) { TestEnv.pages_path }
+ let(:uploads_dir) { File.join(CarrierWave.root, FileUploader.base_dir) }
+ let(:pages_dir) { File.join(TestEnv.pages_path) }
before do
FileUtils.mkdir_p(File.join(uploads_dir, 'parent', 'child', 'the-project'))
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 7a01cef9b4b..d4d4fc86343 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -26,14 +26,18 @@ describe Note, models: true do
it { is_expected.to validate_presence_of(:project) }
context 'when note is on commit' do
- before { allow(subject).to receive(:for_commit?).and_return(true) }
+ before do
+ allow(subject).to receive(:for_commit?).and_return(true)
+ end
it { is_expected.to validate_presence_of(:commit_id) }
it { is_expected.not_to validate_presence_of(:noteable_id) }
end
context 'when note is not on commit' do
- before { allow(subject).to receive(:for_commit?).and_return(false) }
+ before do
+ allow(subject).to receive(:for_commit?).and_return(false)
+ end
it { is_expected.not_to validate_presence_of(:commit_id) }
it { is_expected.to validate_presence_of(:noteable_id) }
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index d58673413c8..cc235ad467e 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -55,4 +55,34 @@ RSpec.describe NotificationSetting, type: :model do
expect(user.notification_settings.for_projects.map(&:project)).to all(have_attributes(pending_delete: false))
end
end
+
+ describe 'event_enabled?' do
+ before do
+ subject.update!(user: create(:user))
+ end
+
+ context 'for an event with a matching column name' do
+ before do
+ subject.update!(events: { new_note: true }.to_json)
+ end
+
+ it 'returns the value of the column' do
+ subject.update!(new_note: false)
+
+ expect(subject.event_enabled?(:new_note)).to be(false)
+ end
+
+ context 'when the column has a nil value' do
+ it 'returns the value from the events hash' do
+ expect(subject.event_enabled?(:new_note)).to be(false)
+ end
+ end
+ end
+
+ context 'for an event without a matching column name' do
+ it 'returns false' do
+ expect(subject.event_enabled?(:foo_event)).to be(false)
+ end
+ end
+ end
end
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 823623d96fa..fa781195608 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -35,6 +35,16 @@ describe PersonalAccessToken, models: true do
end
end
+ describe 'revoke!' do
+ let(:active_personal_access_token) { create(:personal_access_token) }
+
+ it 'revokes the token' do
+ active_personal_access_token.revoke!
+
+ expect(active_personal_access_token.revoked?).to be true
+ end
+ end
+
context "validations" do
let(:personal_access_token) { build(:personal_access_token) }
@@ -51,11 +61,17 @@ describe PersonalAccessToken, models: true do
expect(personal_access_token).to be_valid
end
- it "rejects creating a token with non-API scopes" do
+ it "allows creating a token with read_registry scope" do
+ personal_access_token.scopes = [:read_registry]
+
+ expect(personal_access_token).to be_valid
+ end
+
+ it "rejects creating a token with unavailable scopes" do
personal_access_token.scopes = [:openid, :api]
expect(personal_access_token).not_to be_valid
- expect(personal_access_token.errors[:scopes].first).to eq "can only contain API scopes"
+ expect(personal_access_token.errors[:scopes].first).to eq "can only contain available scopes"
end
end
end
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index 4014d6129ee..e62fd69e567 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -24,7 +24,9 @@ describe BambooService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:build_key) }
it { is_expected.to validate_presence_of(:bamboo_url) }
@@ -60,7 +62,9 @@ describe BambooService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:build_key) }
it { is_expected.not_to validate_presence_of(:bamboo_url) }
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 739cc72b2ff..5f17bbde390 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -8,7 +8,9 @@ describe BugzillaService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
@@ -19,7 +21,9 @@ describe BugzillaService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index 05b602d8106..dd529597067 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -23,7 +23,9 @@ describe BuildkiteService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:token) }
@@ -31,7 +33,9 @@ describe BuildkiteService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:token) }
diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb
index 953e664fb66..de55627dd27 100644
--- a/spec/models/project_services/campfire_service_spec.rb
+++ b/spec/models/project_services/campfire_service_spec.rb
@@ -8,13 +8,17 @@ describe CampfireService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
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 4ca1b8aa7b7..17355c1e6f1 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
@@ -23,7 +23,9 @@ describe ChatMessage::WikiPageMessage, models: true do
context 'without markdown' do
describe '#pretext' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns a message that a new wiki page was created' do
expect(subject.pretext).to eq(
@@ -33,7 +35,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns a message that a wiki page was updated' do
expect(subject.pretext).to eq(
@@ -47,7 +51,9 @@ describe ChatMessage::WikiPageMessage, models: true do
let(:color) { '#345' }
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns the attachment for a new wiki page' do
expect(subject.attachments).to eq([
@@ -60,7 +66,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns the attachment for an updated wiki page' do
expect(subject.attachments).to eq([
@@ -81,7 +89,9 @@ describe ChatMessage::WikiPageMessage, models: true do
describe '#pretext' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns a message that a new wiki page was created' do
expect(subject.pretext).to eq(
@@ -90,7 +100,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns a message that a wiki page was updated' do
expect(subject.pretext).to eq(
@@ -101,7 +113,9 @@ describe ChatMessage::WikiPageMessage, models: true do
describe '#attachments' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns the attachment for a new wiki page' do
expect(subject.attachments).to eq('Wiki page description')
@@ -109,7 +123,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns the attachment for an updated wiki page' do
expect(subject.attachments).to eq('Wiki page description')
@@ -119,7 +135,9 @@ describe ChatMessage::WikiPageMessage, models: true do
describe '#activity' do
context 'when :action == "create"' do
- before { args[:object_attributes][:action] = 'create' }
+ before do
+ args[:object_attributes][:action] = 'create'
+ end
it 'returns the attachment for a new wiki page' do
expect(subject.activity).to eq({
@@ -132,7 +150,9 @@ describe ChatMessage::WikiPageMessage, models: true do
end
context 'when :action == "update"' do
- before { args[:object_attributes][:action] = 'update' }
+ before do
+ args[:object_attributes][:action] = 'update'
+ end
it 'returns the attachment for an updated wiki page' do
expect(subject.activity).to eq({
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 63320931e76..9e574762232 100644
--- a/spec/models/project_services/custom_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb
@@ -8,7 +8,9 @@ describe CustomIssueTrackerService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
@@ -19,7 +21,9 @@ describe CustomIssueTrackerService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index 044737c6026..1400175427f 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -10,7 +10,9 @@ describe DroneCiService, models: true, caching: true do
describe 'validations' do
context 'active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:drone_url) }
@@ -18,7 +20,9 @@ describe DroneCiService, models: true, caching: true do
end
context 'inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
it { is_expected.not_to validate_presence_of(:drone_url) }
diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb
index e6f78898c82..d9b7010e5e5 100644
--- a/spec/models/project_services/emails_on_push_service_spec.rb
+++ b/spec/models/project_services/emails_on_push_service_spec.rb
@@ -3,13 +3,17 @@ require 'spec_helper'
describe EmailsOnPushService do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:recipients) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:recipients) }
end
diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb
index bdeea1db1e3..291fc645a1c 100644
--- a/spec/models/project_services/external_wiki_service_spec.rb
+++ b/spec/models/project_services/external_wiki_service_spec.rb
@@ -9,14 +9,18 @@ describe ExternalWikiService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:external_wiki_url) }
it_behaves_like 'issue tracker service URL attribute', :external_wiki_url
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:external_wiki_url) }
end
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index a97e8c6e4ce..56ace04dd58 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -8,13 +8,17 @@ describe FlowdockService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index a13fbae03eb..65c9e714bd1 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -8,14 +8,18 @@ describe GemnasiumService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:api_key) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
it { is_expected.not_to validate_presence_of(:api_key) }
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 1200ae7eb22..c7c8e9651ab 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -8,13 +8,17 @@ describe HipchatService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index d5a16226d9d..a5c4938b54e 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -10,13 +10,17 @@ describe IrkerService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:recipients) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:recipients) }
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 0ee050196e4..e2b8226124f 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -10,7 +10,9 @@ describe JiraService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_presence_of(:project_key) }
@@ -18,7 +20,9 @@ describe JiraService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:url) }
end
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 0dcf4a4b5d6..858ad595dbf 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -7,31 +7,15 @@ describe KubernetesService, models: true, caching: true do
let(:project) { build_stubbed(:kubernetes_project) }
let(:service) { project.kubernetes_service }
- # We use Kubeclient to interactive with the Kubernetes API. It will
- # GET /api/v1 for a list of resources the API supports. This must be stubbed
- # in addition to any other HTTP requests we expect it to perform.
- let(:discovery_url) { service.api_url + '/api/v1' }
- let(:discovery_response) { { body: kube_discovery_body.to_json } }
-
- let(:pods_url) { service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods" }
- let(:pods_response) { { body: kube_pods_body(kube_pod).to_json } }
-
- def stub_kubeclient_discover
- WebMock.stub_request(:get, discovery_url).to_return(discovery_response)
- end
-
- def stub_kubeclient_pods
- stub_kubeclient_discover
- WebMock.stub_request(:get, pods_url).to_return(pods_response)
- end
-
describe "Associations" do
it { is_expected.to belong_to :project }
end
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.not_to validate_presence_of(:namespace) }
it { is_expected.to validate_presence_of(:api_url) }
@@ -66,7 +50,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:api_url) }
it { is_expected.not_to validate_presence_of(:token) }
@@ -87,7 +73,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'as template' do
- before { subject.template = true }
+ before do
+ subject.template = true
+ end
it 'sets the namespace to the default' do
expect(kube_namespace).not_to be_nil
@@ -96,7 +84,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'with associated project' do
- before { subject.project = project }
+ before do
+ subject.project = project
+ end
it 'sets the namespace to the default' do
expect(kube_namespace).not_to be_nil
@@ -111,6 +101,34 @@ 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'
+ end
+
+ it "returns the user-namespace" do
+ is_expected.to eq('my-namespace')
+ end
+ end
+
+ context 'when service is not assigned to project' do
+ before do
+ service.project = nil
+ end
+
+ it "does not return namespace" do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ describe '#actual_namespace' do
+ subject { service.actual_namespace }
+
+ it "returns the default namespace" do
+ is_expected.to eq(service.send(:default_namespace))
+ end
context 'when namespace is specified' do
before do
@@ -134,6 +152,8 @@ describe KubernetesService, models: true, caching: true do
end
describe '#test' do
+ let(:discovery_url) { 'https://kubernetes.example.com/api/v1' }
+
before do
stub_kubeclient_discover
end
@@ -142,7 +162,8 @@ describe KubernetesService, models: true, caching: true do
let(:discovery_url) { 'https://kubernetes.example.com/prefix/api/v1' }
it 'tests with the prefix' do
- service.api_url = 'https://kubernetes.example.com/prefix/'
+ service.api_url = 'https://kubernetes.example.com/prefix'
+ stub_kubeclient_discover
expect(service.test[:success]).to be_truthy
expect(WebMock).to have_requested(:get, discovery_url).once
@@ -170,9 +191,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'failure' do
- let(:discovery_response) { { status: 404 } }
-
it 'fails to read the discovery endpoint' do
+ WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(status: 404)
+
expect(service.test[:success]).to be_falsy
expect(WebMock).to have_requested(:get, discovery_url).once
end
@@ -188,7 +209,9 @@ describe KubernetesService, models: true, caching: true do
end
context 'namespace is provided' do
- before { subject.namespace = 'my-project' }
+ before do
+ subject.namespace = 'my-project'
+ end
it 'sets the variables' do
expect(subject.predefined_variables).to include(
@@ -258,27 +281,36 @@ describe KubernetesService, models: true, caching: true do
end
describe '#calculate_reactive_cache' do
- before { stub_kubeclient_pods }
subject { service.calculate_reactive_cache }
context 'when service is inactive' do
- before { service.active = false }
+ before do
+ service.active = false
+ end
it { is_expected.to be_nil }
end
context 'when kubernetes responds with valid pods' do
+ before do
+ stub_kubeclient_pods
+ end
+
it { is_expected.to eq(pods: [kube_pod]) }
end
- context 'when kubernetes responds with 500' do
- let(:pods_response) { { status: 500 } }
+ context 'when kubernetes responds with 500s' do
+ before do
+ stub_kubeclient_pods(status: 500)
+ end
it { expect { subject }.to raise_error(KubeException) }
end
- context 'when kubernetes responds with 404' do
- let(:pods_response) { { status: 404 } }
+ context 'when kubernetes responds with 404s' do
+ before do
+ stub_kubeclient_pods(status: 404)
+ end
it { is_expected.to eq(pods: []) }
end
diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb
index facc034f69c..bd50a2d1470 100644
--- a/spec/models/project_services/microsoft_teams_service_spec.rb
+++ b/spec/models/project_services/microsoft_teams_service_spec.rb
@@ -11,14 +11,18 @@ describe MicrosoftTeamsService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:webhook) }
it_behaves_like 'issue tracker service URL attribute', :webhook
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:webhook) }
end
diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb
index a76e909d04d..f4c1a9c94b6 100644
--- a/spec/models/project_services/pivotaltracker_service_spec.rb
+++ b/spec/models/project_services/pivotaltracker_service_spec.rb
@@ -8,13 +8,17 @@ describe PivotaltrackerService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:token) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:token) }
end
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index b761567ad76..c914b32f7a4 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -14,13 +14,17 @@ describe PrometheusService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:api_url) }
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:api_url) }
end
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index a7e7594a7d5..9171d9604ee 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -8,7 +8,9 @@ describe PushoverService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:api_key) }
it { is_expected.to validate_presence_of(:user_key) }
@@ -16,7 +18,9 @@ describe PushoverService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:api_key) }
it { is_expected.not_to validate_presence_of(:user_key) }
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index 0a7b237a051..6631d9040b1 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -8,7 +8,9 @@ describe RedmineService, models: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
@@ -19,7 +21,9 @@ describe RedmineService, models: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index 77b18e1c7d0..7349eb4149a 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -24,7 +24,9 @@ describe TeamcityService, models: true, caching: true do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:build_type) }
it { is_expected.to validate_presence_of(:teamcity_url) }
@@ -60,7 +62,9 @@ describe TeamcityService, models: true, caching: true do
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:build_type) }
it { is_expected.not_to validate_presence_of(:teamcity_url) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 3ed52d42f86..63333b7af1f 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -812,7 +812,7 @@ describe Project, models: true do
context 'when avatar file is uploaded' do
let(:project) { create(:empty_project, :with_avatar) }
- let(:avatar_path) { "/uploads/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
@@ -1005,13 +1005,17 @@ describe Project, models: true do
subject { project.shared_runners_enabled }
context 'are enabled' do
- before { stub_application_setting(shared_runners_enabled: true) }
+ before do
+ stub_application_setting(shared_runners_enabled: true)
+ end
it { is_expected.to be_truthy }
end
context 'are disabled' do
- before { stub_application_setting(shared_runners_enabled: false) }
+ before do
+ stub_application_setting(shared_runners_enabled: false)
+ end
it { is_expected.to be_falsey }
end
@@ -1107,7 +1111,9 @@ describe Project, models: true do
subject { project.pages_deployed? }
context 'if public folder does exist' do
- before { allow(Dir).to receive(:exist?).with(project.public_pages_path).and_return(true) }
+ before do
+ allow(Dir).to receive(:exist?).with(project.public_pages_path).and_return(true)
+ end
it { is_expected.to be_truthy }
end
@@ -1365,7 +1371,9 @@ describe Project, models: true do
subject { project.container_registry_url }
- before { stub_container_registry_config(**registry_settings) }
+ before do
+ stub_container_registry_config(**registry_settings)
+ end
context 'for enabled registry' do
let(:registry_settings) do
@@ -1389,7 +1397,9 @@ describe Project, models: true do
let(:project) { create(:empty_project) }
context 'when container registry is enabled' do
- before { stub_container_registry_config(enabled: true) }
+ before do
+ stub_container_registry_config(enabled: true)
+ end
context 'when tags are present for multi-level registries' do
before do
@@ -1427,7 +1437,9 @@ describe Project, models: true do
end
context 'when container registry is disabled' do
- before { stub_container_registry_config(enabled: false) }
+ before do
+ stub_container_registry_config(enabled: false)
+ end
it 'should not have image tags' do
expect(project).not_to have_container_registry_tags
@@ -1945,7 +1957,9 @@ describe Project, models: true do
describe '#parent_changed?' do
let(:project) { create(:empty_project) }
- before { project.namespace_id = 7 }
+ before do
+ project.namespace_id = 7
+ end
it { expect(project.parent_changed?).to be_truthy }
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 362565506e5..ea3cd5fe10a 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -240,7 +240,9 @@ describe ProjectTeam, models: true do
it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) }
context 'but share_with_group_lock is true' do
- before { project.namespace.update(share_with_group_lock: true) }
+ before do
+ project.namespace.update(share_with_group_lock: true)
+ end
it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::NO_ACCESS) }
it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::NO_ACCESS) }
@@ -389,16 +391,7 @@ describe ProjectTeam, models: true do
end
describe '#max_member_access_for_user_ids' do
- context 'with RequestStore enabled' do
- before do
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
- end
-
+ context 'with RequestStore enabled', :request_store do
include_examples 'max member access for users'
def access_levels(users)
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 224067f58dd..3f5f4eea4a1 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -8,7 +8,10 @@ describe ProjectWiki, models: true do
let(:project_wiki) { ProjectWiki.new(project, user) }
subject { project_wiki }
- before { project_wiki.wiki }
+
+ before do
+ project_wiki.wiki
+ end
describe "#path_with_namespace" do
it "returns the project path with namespace with the .wiki extension" do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 718b7d5e86b..a6d4d92c450 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1905,19 +1905,43 @@ describe Repository, models: true do
end
describe '#is_ancestor?' do
- context 'Gitaly is_ancestor feature enabled' do
- let(:commit) { repository.commit }
- let(:ancestor) { commit.parents.first }
+ let(:commit) { repository.commit }
+ let(:ancestor) { commit.parents.first }
+ context 'with Gitaly enabled' do
+ it 'it is an ancestor' do
+ expect(repository.is_ancestor?(ancestor.id, commit.id)).to eq(true)
+ end
+
+ it 'it is not an ancestor' do
+ expect(repository.is_ancestor?(commit.id, ancestor.id)).to eq(false)
+ end
+
+ it 'returns false on nil-values' do
+ expect(repository.is_ancestor?(nil, commit.id)).to eq(false)
+ expect(repository.is_ancestor?(ancestor.id, nil)).to eq(false)
+ expect(repository.is_ancestor?(nil, nil)).to eq(false)
+ end
+ end
+
+ context 'with Gitaly disabled' do
before do
- allow(Gitlab::GitalyClient).to receive(:enabled?).and_return(true)
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:is_ancestor).and_return(true)
+ allow(Gitlab::GitalyClient).to receive(:enabled?).and_return(false)
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:is_ancestor).and_return(false)
end
- it "asks Gitaly server if it's an ancestor" do
- expect_any_instance_of(Gitlab::GitalyClient::Commit).to receive(:is_ancestor).with(ancestor.id, commit.id)
+ it 'it is an ancestor' do
+ expect(repository.is_ancestor?(ancestor.id, commit.id)).to eq(true)
+ end
+
+ it 'it is not an ancestor' do
+ expect(repository.is_ancestor?(commit.id, ancestor.id)).to eq(false)
+ end
- repository.is_ancestor?(ancestor.id, commit.id)
+ it 'returns false on nil-values' do
+ expect(repository.is_ancestor?(nil, commit.id)).to eq(false)
+ expect(repository.is_ancestor?(ancestor.id, nil)).to eq(false)
+ expect(repository.is_ancestor?(nil, nil)).to eq(false)
end
end
end
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index c1fe1b06c52..1754253e0f2 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -9,7 +9,10 @@ describe Route, models: true do
end
describe 'validations' do
- before { route }
+ before do
+ expect(route).to be_persisted
+ end
+
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
@@ -59,7 +62,9 @@ describe Route, models: true do
context 'path update' do
context 'when route name is set' do
- before { route.update_attributes(path: 'bar') }
+ before do
+ route.update_attributes(path: 'bar')
+ end
it 'updates children routes with new path' do
expect(described_class.exists?(path: 'bar')).to be_truthy
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index a83726b48a0..1a1bbd60504 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -987,7 +987,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/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)
@@ -1584,7 +1584,9 @@ describe User, models: true do
end
context 'user is member of the top group' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
if Group.supports_nested_groups?
it 'returns all groups' do
@@ -1602,7 +1604,9 @@ describe User, models: true do
end
context 'user is member of the first child (internal node), branch 1', :nested_groups do
- before { nested_group_1.add_owner(user) }
+ before do
+ nested_group_1.add_owner(user)
+ end
it 'returns the groups in the hierarchy' do
is_expected.to match_array [
@@ -1613,7 +1617,9 @@ describe User, models: true do
end
context 'user is member of the first child (internal node), branch 2', :nested_groups do
- before { nested_group_2.add_owner(user) }
+ before do
+ nested_group_2.add_owner(user)
+ end
it 'returns the groups in the hierarchy' do
is_expected.to match_array [
@@ -1624,7 +1630,9 @@ describe User, models: true do
end
context 'user is member of the last child (leaf node)', :nested_groups do
- before { nested_group_1_1.add_owner(user) }
+ before do
+ nested_group_1_1.add_owner(user)
+ end
it 'returns the groups in the hierarchy' do
is_expected.to match_array [
diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb
index 3f4ce222b60..48a139d4b83 100644
--- a/spec/policies/ci/build_policy_spec.rb
+++ b/spec/policies/ci/build_policy_spec.rb
@@ -10,7 +10,9 @@ describe Ci::BuildPolicy, :models do
end
shared_context 'public pipelines disabled' do
- before { project.update_attribute(:public_builds, false) }
+ before do
+ project.update_attribute(:public_builds, false)
+ end
end
describe '#rules' do
@@ -54,7 +56,9 @@ describe Ci::BuildPolicy, :models do
let(:project) { create(:empty_project, :public) }
context 'team member is a guest' do
- before { project.team << [user, :guest] }
+ before do
+ project.team << [user, :guest]
+ end
context 'when public builds are enabled' do
it 'includes ability to read build' do
@@ -72,7 +76,9 @@ describe Ci::BuildPolicy, :models do
end
context 'team member is a reporter' do
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
context 'when public builds are enabled' do
it 'includes ability to read build' do
diff --git a/spec/policies/deploy_key_policy_spec.rb b/spec/policies/deploy_key_policy_spec.rb
new file mode 100644
index 00000000000..28e10f0bfe2
--- /dev/null
+++ b/spec/policies/deploy_key_policy_spec.rb
@@ -0,0 +1,56 @@
+require 'spec_helper'
+
+describe DeployKeyPolicy, models: true do
+ subject { described_class.abilities(current_user, deploy_key).to_set }
+
+ describe 'updating a deploy_key' do
+ context 'when a regular user' do
+ let(:current_user) { create(:user) }
+
+ context 'tries to update private deploy key attached to project' do
+ let(:deploy_key) { create(:deploy_key, public: false) }
+ let(:project) { create(:project_empty_repo) }
+
+ before do
+ project.add_master(current_user)
+ project.deploy_keys << deploy_key
+ end
+
+ it { is_expected.to include(:update_deploy_key) }
+ end
+
+ context 'tries to update private deploy key attached to other project' do
+ let(:deploy_key) { create(:deploy_key, public: false) }
+ let(:other_project) { create(:project_empty_repo) }
+
+ before do
+ other_project.deploy_keys << deploy_key
+ end
+
+ it { is_expected.not_to include(: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) }
+ end
+ end
+
+ context 'when an admin user' do
+ let(:current_user) { create(:user, :admin) }
+
+ context ' tries to update private deploy key' do
+ let(:deploy_key) { create(:deploy_key, public: false) }
+
+ it { is_expected.to include(: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) }
+ end
+ end
+ end
+end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 0d3af1f4499..848fd547e10 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -139,6 +139,18 @@ describe ProjectPolicy, models: true do
is_expected.not_to include(:read_build, :read_pipeline)
end
end
+
+ context 'when builds are disabled' do
+ before do
+ project.project_feature.update(
+ builds_access_level: ProjectFeature::DISABLED)
+ end
+
+ it do
+ is_expected.not_to include(:read_build)
+ is_expected.to include(:read_pipeline)
+ end
+ end
end
context 'reporter' do
diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb
index e1771b636b8..d2b2528c57a 100644
--- a/spec/policies/project_snippet_policy_spec.rb
+++ b/spec/policies/project_snippet_policy_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe ProjectSnippetPolicy, models: true do
let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:empty_project, :public) }
let(:author_permissions) do
[
@@ -78,7 +78,9 @@ describe ProjectSnippetPolicy, models: true do
context 'project team member external user' do
subject { abilities(external_user, :internal) }
- before { project.team << [external_user, :developer] }
+ before do
+ project.team << [external_user, :developer]
+ end
it do
is_expected.to include(:read_project_snippet)
@@ -107,7 +109,7 @@ describe ProjectSnippetPolicy, models: true do
end
context 'snippet author' do
- let(:snippet) { create(:project_snippet, :private, author: regular_user) }
+ let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) }
subject { described_class.abilities(regular_user, snippet).to_set }
@@ -120,7 +122,9 @@ describe ProjectSnippetPolicy, models: true do
context 'project team member normal user' do
subject { abilities(regular_user, :private) }
- before { project.team << [regular_user, :developer] }
+ before do
+ project.team << [regular_user, :developer]
+ end
it do
is_expected.to include(:read_project_snippet)
@@ -131,7 +135,9 @@ describe ProjectSnippetPolicy, models: true do
context 'project team member external user' do
subject { abilities(external_user, :private) }
- before { project.team << [external_user, :developer] }
+ before do
+ project.team << [external_user, :developer]
+ end
it do
is_expected.to include(:read_project_snippet)
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index 44720fc4448..f5a14b1d04d 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -132,6 +132,11 @@ describe MergeRequestPresenter do
it 'does not present related issues links' do
is_expected.not_to match("#{project.full_path}/issues/#{issue_b.iid}")
end
+
+ it 'appends status when closing issue is already closed' do
+ issue_a.close
+ is_expected.to match('(closed)')
+ end
end
describe '#mentioned_issues_links' do
@@ -147,6 +152,11 @@ describe MergeRequestPresenter do
it 'does not present closing issues links' do
is_expected.not_to match("#{project.full_path}/issues/#{issue_a.iid}")
end
+
+ it 'appends status when mentioned issue is already closed' do
+ issue_b.close
+ is_expected.to match('(closed)')
+ end
end
describe '#assign_to_closing_issues_link' do
diff --git a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb
index 6443f86b6a1..5c39e1b5f96 100644
--- a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb
+++ b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb
@@ -51,10 +51,6 @@ describe Projects::Settings::DeployKeysPresenter do
expect(presenter.available_project_keys).not_to be_empty
end
- it 'returns false if any available_project_keys are enabled' do
- expect(presenter.any_available_project_keys_enabled?).to eq(true)
- end
-
it 'returns the available_project_keys size' do
expect(presenter.available_project_keys_size).to eq(1)
end
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index bbdef0aeb1b..6d822b5cb4f 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -9,7 +9,9 @@ describe API::AwardEmoji do
let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) }
let!(:note) { create(:note, project: project, noteable: issue) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do
context 'on an issue' do
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index 6b637a03b6f..b8ca73c321c 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -34,7 +34,9 @@ describe API::CommitStatuses do
let!(:status6) { create_status(master, status: 'success') }
context 'latest commit statuses' do
- before { get api(get_url, reporter) }
+ before do
+ get api(get_url, reporter)
+ end
it 'returns latest commit statuses' do
expect(response).to have_http_status(200)
@@ -48,7 +50,9 @@ describe API::CommitStatuses do
end
context 'all commit statuses' do
- before { get api(get_url, reporter), all: 1 }
+ before do
+ get api(get_url, reporter), all: 1
+ end
it 'returns all commit statuses' do
expect(response).to have_http_status(200)
@@ -61,7 +65,9 @@ describe API::CommitStatuses do
end
context 'latest commit statuses for specific ref' do
- before { get api(get_url, reporter), ref: 'develop' }
+ before do
+ get api(get_url, reporter), ref: 'develop'
+ end
it 'returns latest commit statuses for specific ref' do
expect(response).to have_http_status(200)
@@ -72,7 +78,9 @@ describe API::CommitStatuses do
end
context 'latest commit statues for specific name' do
- before { get api(get_url, reporter), name: 'coverage' }
+ before do
+ get api(get_url, reporter), name: 'coverage'
+ end
it 'return latest commit statuses for specific name' do
expect(response).to have_http_status(200)
@@ -85,7 +93,9 @@ describe API::CommitStatuses do
end
context 'ci commit does not exist' do
- before { get api(get_url, reporter) }
+ before do
+ get api(get_url, reporter)
+ end
it 'returns empty array' do
expect(response.status).to eq 200
@@ -95,7 +105,9 @@ describe API::CommitStatuses do
end
context "guest user" do
- before { get api(get_url, guest) }
+ before do
+ get api(get_url, guest)
+ end
it "does not return project commits" do
expect(response).to have_http_status(403)
@@ -103,7 +115,9 @@ describe API::CommitStatuses do
end
context "unauthorized user" do
- before { get api(get_url) }
+ before do
+ get api(get_url)
+ end
it "does not return project commits" do
expect(response).to have_http_status(401)
@@ -209,7 +223,9 @@ describe API::CommitStatuses do
end
context 'when status is invalid' do
- before { post api(post_url, developer), state: 'invalid' }
+ before do
+ post api(post_url, developer), state: 'invalid'
+ end
it 'does not create commit status' do
expect(response).to have_http_status(400)
@@ -217,7 +233,9 @@ describe API::CommitStatuses do
end
context 'when request without a state made' do
- before { post api(post_url, developer) }
+ before do
+ post api(post_url, developer)
+ end
it 'does not create commit status' do
expect(response).to have_http_status(400)
@@ -226,7 +244,10 @@ describe API::CommitStatuses do
context 'when commit SHA is invalid' do
let(:sha) { 'invalid_sha' }
- before { post api(post_url, developer), state: 'running' }
+
+ before do
+ post api(post_url, developer), state: 'running'
+ end
it 'returns not found error' do
expect(response).to have_http_status(404)
@@ -248,7 +269,9 @@ describe API::CommitStatuses do
end
context 'reporter user' do
- before { post api(post_url, reporter), state: 'running' }
+ before do
+ post api(post_url, reporter), state: 'running'
+ end
it 'does not create commit status' do
expect(response).to have_http_status(403)
@@ -256,7 +279,9 @@ describe API::CommitStatuses do
end
context 'guest user' do
- before { post api(post_url, guest), state: 'running' }
+ before do
+ post api(post_url, guest), state: 'running'
+ end
it 'does not create commit status' do
expect(response).to have_http_status(403)
@@ -264,7 +289,9 @@ describe API::CommitStatuses do
end
context 'unauthorized user' do
- before { post api(post_url) }
+ before do
+ post api(post_url)
+ end
it 'does not create commit status' do
expect(response).to have_http_status(401)
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index b0c265b6453..0dad547735d 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -9,11 +9,15 @@ describe API::Commits do
let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') }
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
describe "List repository commits" do
context "authorized user" do
- before { project.team << [user2, :reporter] }
+ before do
+ project.team << [user2, :reporter]
+ end
it "returns project commits" do
commit = project.repository.commit
@@ -514,7 +518,9 @@ describe API::Commits do
describe "Get the diff of a commit" do
context "authorized user" do
- before { project.team << [user2, :reporter] }
+ before do
+ project.team << [user2, :reporter]
+ end
it "returns the diff of the selected commit" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user)
diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb
index 843e9862b0c..9c260f88f56 100644
--- a/spec/requests/api/deploy_keys_spec.rb
+++ b/spec/requests/api/deploy_keys_spec.rb
@@ -13,7 +13,7 @@ describe API::DeployKeys do
describe 'GET /deploy_keys' do
context 'when unauthenticated' do
- it 'should return authentication error' do
+ it 'returns authentication error' do
get api('/deploy_keys')
expect(response.status).to eq(401)
@@ -21,7 +21,7 @@ describe API::DeployKeys do
end
context 'when authenticated as non-admin user' do
- it 'should return a 403 error' do
+ it 'returns a 403 error' do
get api('/deploy_keys', user)
expect(response.status).to eq(403)
@@ -29,7 +29,7 @@ describe API::DeployKeys do
end
context 'when authenticated as admin' do
- it 'should return all deploy keys' do
+ it 'returns all deploy keys' do
get api('/deploy_keys', admin)
expect(response.status).to eq(200)
@@ -41,9 +41,11 @@ describe API::DeployKeys do
end
describe 'GET /projects/:id/deploy_keys' do
- before { deploy_key }
+ before do
+ deploy_key
+ end
- it 'should return array of ssh keys' do
+ it 'returns array of ssh keys' do
get api("/projects/#{project.id}/deploy_keys", admin)
expect(response).to have_http_status(200)
@@ -54,14 +56,14 @@ describe API::DeployKeys do
end
describe 'GET /projects/:id/deploy_keys/:key_id' do
- it 'should return a single key' do
+ it 'returns a single key' do
get api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin)
expect(response).to have_http_status(200)
expect(json_response['title']).to eq(deploy_key.title)
end
- it 'should return 404 Not Found with invalid ID' do
+ it 'returns 404 Not Found with invalid ID' do
get api("/projects/#{project.id}/deploy_keys/404", admin)
expect(response).to have_http_status(404)
@@ -69,26 +71,26 @@ describe API::DeployKeys do
end
describe 'POST /projects/:id/deploy_keys' do
- it 'should not create an invalid ssh key' do
+ it 'does not create an invalid ssh key' do
post api("/projects/#{project.id}/deploy_keys", admin), { title: 'invalid key' }
expect(response).to have_http_status(400)
expect(json_response['error']).to eq('key is missing')
end
- it 'should not create a key without title' do
+ it 'does not create a key without title' do
post api("/projects/#{project.id}/deploy_keys", admin), key: 'some key'
expect(response).to have_http_status(400)
expect(json_response['error']).to eq('title is missing')
end
- it 'should create new ssh key' do
+ it 'creates new ssh key' do
key_attrs = attributes_for :another_key
expect do
post api("/projects/#{project.id}/deploy_keys", admin), key_attrs
- end.to change{ project.deploy_keys.count }.by(1)
+ end.to change { project.deploy_keys.count }.by(1)
end
it 'returns an existing ssh key when attempting to add a duplicate' do
@@ -117,10 +119,55 @@ describe API::DeployKeys do
end
end
+ describe 'PUT /projects/:id/deploy_keys/:key_id' do
+ let(:private_deploy_key) { create(:another_deploy_key, public: false) }
+ let(:project_private_deploy_key) do
+ create(:deploy_keys_project, project: project, deploy_key: private_deploy_key)
+ end
+
+ it 'updates a public deploy key as admin' do
+ expect do
+ put api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin), { title: 'new title' }
+ end.not_to change(deploy_key, :title)
+
+ expect(response).to have_http_status(200)
+ end
+
+ it 'does not update a public deploy key as non admin' do
+ expect do
+ put api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", user), { title: 'new title' }
+ end.not_to change(deploy_key, :title)
+
+ expect(response).to have_http_status(404)
+ end
+
+ it 'does not update a private key with invalid title' do
+ project_private_deploy_key
+
+ expect do
+ put api("/projects/#{project.id}/deploy_keys/#{private_deploy_key.id}", admin), { title: '' }
+ end.not_to change(deploy_key, :title)
+
+ expect(response).to have_http_status(400)
+ end
+
+ it 'updates a private ssh key with correct attributes' do
+ project_private_deploy_key
+
+ put api("/projects/#{project.id}/deploy_keys/#{private_deploy_key.id}", admin), { title: 'new title', can_push: true }
+
+ expect(json_response['id']).to eq(private_deploy_key.id)
+ expect(json_response['title']).to eq('new title')
+ expect(json_response['can_push']).to eq(true)
+ end
+ end
+
describe 'DELETE /projects/:id/deploy_keys/:key_id' do
- before { deploy_key }
+ before do
+ deploy_key
+ end
- it 'should delete existing key' do
+ it 'deletes existing key' do
expect do
delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin)
@@ -128,7 +175,7 @@ describe API::DeployKeys do
end.to change{ project.deploy_keys.count }.by(-1)
end
- it 'should return 404 Not Found with invalid ID' do
+ it 'returns 404 Not Found with invalid ID' do
delete api("/projects/#{project.id}/deploy_keys/404", admin)
expect(response).to have_http_status(404)
@@ -150,7 +197,7 @@ describe API::DeployKeys do
end
context 'when authenticated as non-admin user' do
- it 'should return a 404 error' do
+ it 'returns a 404 error' do
post api("/projects/#{project2.id}/deploy_keys/#{deploy_key.id}/enable", user)
expect(response).to have_http_status(404)
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index d325c6eff9d..c5ec8be4f21 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -13,7 +13,9 @@ describe API::Files do
let(:author_email) { 'user@example.org' }
let(:author_name) { 'John Doe' }
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
def route(file_path = nil)
"/projects/#{project.id}/repository/files/#{file_path}"
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index ed392acc607..191c60aba31 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -55,40 +55,62 @@ describe API::Helpers do
subject { current_user }
describe "Warden authentication" do
- before { doorkeeper_guard_returns false }
+ before do
+ doorkeeper_guard_returns false
+ end
context "with invalid credentials" do
context "GET request" do
- before { env['REQUEST_METHOD'] = 'GET' }
+ before do
+ env['REQUEST_METHOD'] = 'GET'
+ end
+
it { is_expected.to be_nil }
end
end
context "with valid credentials" do
- before { warden_authenticate_returns user }
+ before do
+ warden_authenticate_returns user
+ end
context "GET request" do
- before { env['REQUEST_METHOD'] = 'GET' }
+ before do
+ env['REQUEST_METHOD'] = 'GET'
+ end
+
it { is_expected.to eq(user) }
end
context "HEAD request" do
- before { env['REQUEST_METHOD'] = 'HEAD' }
+ before do
+ env['REQUEST_METHOD'] = 'HEAD'
+ end
+
it { is_expected.to eq(user) }
end
context "PUT request" do
- before { env['REQUEST_METHOD'] = 'PUT' }
+ before do
+ env['REQUEST_METHOD'] = 'PUT'
+ end
+
it { is_expected.to be_nil }
end
context "POST request" do
- before { env['REQUEST_METHOD'] = 'POST' }
+ before do
+ env['REQUEST_METHOD'] = 'POST'
+ end
+
it { is_expected.to be_nil }
end
context "DELETE request" do
- before { env['REQUEST_METHOD'] = 'DELETE' }
+ before do
+ env['REQUEST_METHOD'] = 'DELETE'
+ end
+
it { is_expected.to be_nil }
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index cf232e7ff69..86e15d896df 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -15,21 +15,43 @@ describe API::Internal do
end
end
- describe "GET /internal/broadcast_message" do
- context "broadcast message exists" do
- let!(:broadcast_message) { create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow ) }
+ describe 'GET /internal/broadcast_message' do
+ context 'broadcast message exists' do
+ let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }
- it do
- get api("/internal/broadcast_message"), secret_token: secret_token
+ it 'returns one broadcast message' do
+ get api('/internal/broadcast_message'), secret_token: secret_token
expect(response).to have_http_status(200)
- expect(json_response["message"]).to eq(broadcast_message.message)
+ expect(json_response['message']).to eq(broadcast_message.message)
end
end
- context "broadcast message doesn't exist" do
- it do
- get api("/internal/broadcast_message"), secret_token: secret_token
+ context 'broadcast message does not exist' do
+ it 'returns nothing' do
+ 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
+ context 'broadcast message(s) exist' do
+ let!(:broadcast_message) { create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now ) }
+
+ it 'returns active broadcast message(s)' do
+ get api('/internal/broadcast_messages'), secret_token: secret_token
+
+ expect(response).to have_http_status(200)
+ expect(json_response[0]['message']).to eq(broadcast_message.message)
+ end
+ end
+
+ context 'broadcast message does not exist' do
+ it 'returns nothing' do
+ get api('/internal/broadcast_messages'), secret_token: secret_token
expect(response).to have_http_status(200)
expect(json_response).to be_empty
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index e5e5872dc1f..8d647eb1c7e 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -11,7 +11,7 @@ describe API::Jobs, :api do
ref: project.default_branch)
end
- let!(:build) { create(:ci_build, pipeline: pipeline) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
let(:user) { create(:user) }
let(:api_user) { user }
@@ -42,13 +42,13 @@ describe API::Jobs, :api do
end
it 'returns pipeline data' do
- json_build = json_response.first
+ json_job = json_response.first
- expect(json_build['pipeline']).not_to be_empty
- expect(json_build['pipeline']['id']).to eq build.pipeline.id
- expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
- expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
- expect(json_build['pipeline']['status']).to eq build.pipeline.status
+ expect(json_job['pipeline']).not_to be_empty
+ expect(json_job['pipeline']['id']).to eq job.pipeline.id
+ expect(json_job['pipeline']['ref']).to eq job.pipeline.ref
+ expect(json_job['pipeline']['sha']).to eq job.pipeline.sha
+ expect(json_job['pipeline']['status']).to eq job.pipeline.status
end
context 'filter project with one scope element' do
@@ -79,7 +79,7 @@ describe API::Jobs, :api do
context 'unauthorized user' do
let(:api_user) { nil }
- it 'does not return project builds' do
+ it 'does not return project jobs' do
expect(response).to have_http_status(401)
end
end
@@ -105,13 +105,13 @@ describe API::Jobs, :api do
end
it 'returns pipeline data' do
- json_build = json_response.first
+ json_job = json_response.first
- expect(json_build['pipeline']).not_to be_empty
- expect(json_build['pipeline']['id']).to eq build.pipeline.id
- expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
- expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
- expect(json_build['pipeline']['status']).to eq build.pipeline.status
+ expect(json_job['pipeline']).not_to be_empty
+ expect(json_job['pipeline']['id']).to eq job.pipeline.id
+ expect(json_job['pipeline']['ref']).to eq job.pipeline.ref
+ expect(json_job['pipeline']['sha']).to eq job.pipeline.sha
+ expect(json_job['pipeline']['status']).to eq job.pipeline.status
end
context 'filter jobs with one scope element' do
@@ -140,7 +140,7 @@ describe API::Jobs, :api do
context 'jobs in different pipelines' do
let!(:pipeline2) { create(:ci_empty_pipeline, project: project) }
- let!(:build2) { create(:ci_build, pipeline: pipeline2) }
+ let!(:job2) { create(:ci_build, pipeline: pipeline2) }
it 'excludes jobs from other pipelines' do
json_response.each { |job| expect(job['pipeline']['id']).to eq(pipeline.id) }
@@ -159,7 +159,7 @@ describe API::Jobs, :api do
describe 'GET /projects/:id/jobs/:job_id' do
before do
- get api("/projects/#{project.id}/jobs/#{build.id}", api_user)
+ get api("/projects/#{project.id}/jobs/#{job.id}", api_user)
end
context 'authorized user' do
@@ -169,12 +169,13 @@ describe API::Jobs, :api do
end
it 'returns pipeline data' do
- json_build = json_response
- expect(json_build['pipeline']).not_to be_empty
- expect(json_build['pipeline']['id']).to eq build.pipeline.id
- expect(json_build['pipeline']['ref']).to eq build.pipeline.ref
- expect(json_build['pipeline']['sha']).to eq build.pipeline.sha
- expect(json_build['pipeline']['status']).to eq build.pipeline.status
+ json_job = json_response
+
+ expect(json_job['pipeline']).not_to be_empty
+ expect(json_job['pipeline']['id']).to eq job.pipeline.id
+ expect(json_job['pipeline']['ref']).to eq job.pipeline.ref
+ expect(json_job['pipeline']['sha']).to eq job.pipeline.sha
+ expect(json_job['pipeline']['status']).to eq job.pipeline.status
end
end
@@ -189,11 +190,11 @@ describe API::Jobs, :api do
describe 'GET /projects/:id/jobs/:job_id/artifacts' do
before do
- get api("/projects/#{project.id}/jobs/#{build.id}/artifacts", api_user)
+ get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
end
context 'job with artifacts' do
- let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
context 'authorized user' do
let(:download_headers) do
@@ -204,7 +205,7 @@ describe API::Jobs, :api do
it 'returns specific job artifacts' do
expect(response).to have_http_status(200)
expect(response.headers).to include(download_headers)
- expect(response.body).to match_file(build.artifacts_file.file.file)
+ expect(response.body).to match_file(job.artifacts_file.file.file)
end
end
@@ -224,14 +225,14 @@ describe API::Jobs, :api do
describe 'GET /projects/:id/artifacts/:ref_name/download?job=name' do
let(:api_user) { reporter }
- let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
before do
- build.success
+ job.success
end
- def get_for_ref(ref = pipeline.ref, job = build.name)
- get api("/projects/#{project.id}/jobs/artifacts/#{ref}/download", api_user), job: job
+ def get_for_ref(ref = pipeline.ref, job_name = job.name)
+ get api("/projects/#{project.id}/jobs/artifacts/#{ref}/download", api_user), job: job_name
end
context 'when not logged in' do
@@ -285,7 +286,7 @@ describe API::Jobs, :api do
let(:download_headers) do
{ 'Content-Transfer-Encoding' => 'binary',
'Content-Disposition' =>
- "attachment; filename=#{build.artifacts_file.filename}" }
+ "attachment; filename=#{job.artifacts_file.filename}" }
end
it { expect(response).to have_http_status(200) }
@@ -321,16 +322,16 @@ describe API::Jobs, :api do
end
describe 'GET /projects/:id/jobs/:job_id/trace' do
- let(:build) { create(:ci_build, :trace, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :trace, pipeline: pipeline) }
before do
- get api("/projects/#{project.id}/jobs/#{build.id}/trace", api_user)
+ get api("/projects/#{project.id}/jobs/#{job.id}/trace", api_user)
end
context 'authorized user' do
it 'returns specific job trace' do
expect(response).to have_http_status(200)
- expect(response.body).to eq(build.trace.raw)
+ expect(response.body).to eq(job.trace.raw)
end
end
@@ -345,7 +346,7 @@ describe API::Jobs, :api do
describe 'POST /projects/:id/jobs/:job_id/cancel' do
before do
- post api("/projects/#{project.id}/jobs/#{build.id}/cancel", api_user)
+ post api("/projects/#{project.id}/jobs/#{job.id}/cancel", api_user)
end
context 'authorized user' do
@@ -375,10 +376,10 @@ describe API::Jobs, :api do
end
describe 'POST /projects/:id/jobs/:job_id/retry' do
- let(:build) { create(:ci_build, :canceled, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :canceled, pipeline: pipeline) }
before do
- post api("/projects/#{project.id}/jobs/#{build.id}/retry", api_user)
+ post api("/projects/#{project.id}/jobs/#{job.id}/retry", api_user)
end
context 'authorized user' do
@@ -410,28 +411,29 @@ describe API::Jobs, :api do
describe 'POST /projects/:id/jobs/:job_id/erase' do
before do
- post api("/projects/#{project.id}/jobs/#{build.id}/erase", user)
+ post api("/projects/#{project.id}/jobs/#{job.id}/erase", user)
end
context 'job is erasable' do
- let(:build) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :trace, :artifacts, :success, project: project, pipeline: pipeline) }
it 'erases job content' do
expect(response).to have_http_status(201)
- expect(build).not_to have_trace
- expect(build.artifacts_file.exists?).to be_falsy
- expect(build.artifacts_metadata.exists?).to be_falsy
+ expect(job).not_to have_trace
+ expect(job.artifacts_file.exists?).to be_falsy
+ expect(job.artifacts_metadata.exists?).to be_falsy
end
it 'updates job' do
- build.reload
- expect(build.erased_at).to be_truthy
- expect(build.erased_by).to eq(user)
+ job.reload
+
+ expect(job.erased_at).to be_truthy
+ expect(job.erased_by).to eq(user)
end
end
context 'job is not erasable' do
- let(:build) { create(:ci_build, :trace, project: project, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :trace, project: project, pipeline: pipeline) }
it 'responds with forbidden' do
expect(response).to have_http_status(403)
@@ -439,25 +441,25 @@ describe API::Jobs, :api do
end
end
- describe 'POST /projects/:id/jobs/:build_id/artifacts/keep' do
+ describe 'POST /projects/:id/jobs/:job_id/artifacts/keep' do
before do
- post api("/projects/#{project.id}/jobs/#{build.id}/artifacts/keep", user)
+ post api("/projects/#{project.id}/jobs/#{job.id}/artifacts/keep", user)
end
context 'artifacts did not expire' do
- let(:build) do
+ let(:job) do
create(:ci_build, :trace, :artifacts, :success,
project: project, pipeline: pipeline, artifacts_expire_at: Time.now + 7.days)
end
it 'keeps artifacts' do
expect(response).to have_http_status(200)
- expect(build.reload.artifacts_expire_at).to be_nil
+ expect(job.reload.artifacts_expire_at).to be_nil
end
end
context 'no artifacts' do
- let(:build) { create(:ci_build, project: project, pipeline: pipeline) }
+ let(:job) { create(:ci_build, project: project, pipeline: pipeline) }
it 'responds with not found' do
expect(response).to have_http_status(404)
@@ -467,18 +469,18 @@ describe API::Jobs, :api do
describe 'POST /projects/:id/jobs/:job_id/play' do
before do
- post api("/projects/#{project.id}/jobs/#{build.id}/play", api_user)
+ post api("/projects/#{project.id}/jobs/#{job.id}/play", api_user)
end
context 'on an playable job' do
- let(:build) { create(:ci_build, :manual, project: project, pipeline: pipeline) }
+ let(:job) { create(:ci_build, :manual, project: project, pipeline: pipeline) }
context 'when user is authorized to trigger a manual action' do
it 'plays the job' do
expect(response).to have_http_status(200)
expect(json_response['user']['id']).to eq(user.id)
- expect(json_response['id']).to eq(build.id)
- expect(build.reload).to be_pending
+ expect(json_response['id']).to eq(job.id)
+ expect(job.reload).to be_pending
end
end
@@ -487,7 +489,7 @@ describe API::Jobs, :api do
let(:api_user) { create(:user) }
it 'does not trigger a manual action' do
- expect(build.reload).to be_manual
+ expect(job.reload).to be_manual
expect(response).to have_http_status(404)
end
end
@@ -496,7 +498,7 @@ describe API::Jobs, :api do
let(:api_user) { reporter }
it 'does not trigger a manual action' do
- expect(build.reload).to be_manual
+ expect(job.reload).to be_manual
expect(response).to have_http_status(403)
end
end
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
index ab957c72984..f534332ca6c 100644
--- a/spec/requests/api/keys_spec.rb
+++ b/spec/requests/api/keys_spec.rb
@@ -4,11 +4,9 @@ describe API::Keys do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
- let(:email) { create(:email, user: user) }
+ let(:email) { create(:email, user: user) }
describe 'GET /keys/:uid' do
- before { admin }
-
context 'when unauthenticated' do
it 'returns authentication error' do
get api("/keys/#{key.id}")
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index 0c6b55c1630..f7e2f1908bb 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -339,7 +339,9 @@ describe API::Labels do
end
context "when user is already subscribed to label" do
- before { label1.subscribe(user, project) }
+ before do
+ label1.subscribe(user, project)
+ end
it "returns 304" do
post api("/projects/#{project.id}/labels/#{label1.id}/subscribe", user)
@@ -358,7 +360,9 @@ describe API::Labels do
end
describe "POST /projects/:id/labels/:label_id/unsubscribe" do
- before { label1.subscribe(user, project) }
+ before do
+ label1.subscribe(user, project)
+ end
context "when label_id is a label title" do
it "unsubscribes from the label" do
@@ -381,7 +385,9 @@ describe API::Labels do
end
context "when user is already unsubscribed from label" do
- before { label1.unsubscribe(user, project) }
+ before do
+ label1.unsubscribe(user, project)
+ end
it "returns 304" do
post api("/projects/#{project.id}/labels/#{label1.id}/unsubscribe", user)
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index dd74351a2b1..40934c25afc 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -6,7 +6,9 @@ describe API::Milestones do
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 { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
describe 'GET /projects/:id/milestones' do
it 'returns project milestones' do
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 6afcd237c3c..03f2b5950ee 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -28,7 +28,9 @@ describe API::Notes do
system: true
end
- before { project.team << [user, :reporter] }
+ before do
+ project.team << [user, :reporter]
+ end
describe "GET /projects/:id/noteable/:noteable_id/notes" do
context "when noteable is an Issue" do
@@ -58,7 +60,9 @@ describe API::Notes do
end
context "and issue is confidential" do
- before { ext_issue.update_attributes(confidential: true) }
+ before do
+ ext_issue.update_attributes(confidential: true)
+ end
it "returns 404" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
@@ -150,7 +154,9 @@ describe API::Notes do
end
context "when issue is confidential" do
- before { issue.update_attributes(confidential: true) }
+ before do
+ issue.update_attributes(confidential: true)
+ end
it "returns 404" do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index 9e6957e9922..258085e503f 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -10,7 +10,9 @@ describe API::Pipelines do
ref: project.default_branch, user: user)
end
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
describe 'GET /projects/:id/pipelines ' do
context 'authorized user' do
@@ -285,7 +287,9 @@ describe API::Pipelines do
describe 'POST /projects/:id/pipeline ' do
context 'authorized user' do
context 'with gitlab-ci.yml' do
- before { stub_ci_pipeline_to_return_yaml_file }
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
it 'creates and returns a new pipeline' do
expect do
@@ -419,7 +423,9 @@ describe API::Pipelines do
context 'user without proper access rights' do
let!(:reporter) { create(:user) }
- before { project.team << [reporter, :reporter] }
+ before do
+ project.team << [reporter, :reporter]
+ end
it 'rejects the action' do
post api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter)
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 3ab1764f5c3..4d4631322b1 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -36,11 +36,34 @@ describe API::ProjectSnippets do
end
end
+ describe 'GET /projects/:project_id/snippets/:id' do
+ let(:user) { create(:user) }
+ let(:snippet) { create(:project_snippet, :public, project: project) }
+
+ it 'returns snippet json' do
+ get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
+
+ expect(response).to have_http_status(200)
+
+ expect(json_response['title']).to eq(snippet.title)
+ expect(json_response['description']).to eq(snippet.description)
+ expect(json_response['file_name']).to eq(snippet.file_name)
+ end
+
+ it 'returns 404 for invalid snippet id' do
+ get api("/projects/#{project.id}/snippets/1234", user)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Not found')
+ end
+ end
+
describe 'POST /projects/:project_id/snippets/' do
let(:params) do
{
title: 'Test Title',
file_name: 'test.rb',
+ description: 'test description',
code: 'puts "hello world"',
visibility: 'public'
}
@@ -52,6 +75,7 @@ describe API::ProjectSnippets do
expect(response).to have_http_status(201)
snippet = ProjectSnippet.find(json_response['id'])
expect(snippet.content).to eq(params[:code])
+ expect(snippet.description).to eq(params[:description])
expect(snippet.title).to eq(params[:title])
expect(snippet.file_name).to eq(params[:file_name])
expect(snippet.visibility_level).to eq(Snippet::PUBLIC)
@@ -106,12 +130,14 @@ describe API::ProjectSnippets do
it 'updates snippet' do
new_content = 'New content'
+ new_description = 'New description'
- put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin), code: new_content
+ put api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin), code: new_content, description: new_description
expect(response).to have_http_status(200)
snippet.reload
expect(snippet.content).to eq(new_content)
+ expect(snippet.description).to eq(new_description)
end
it 'returns 404 for invalid snippet id' do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 86c57204971..d92262a4c99 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -398,6 +398,15 @@ describe API::Projects do
expect(json_response['tag_list']).to eq(%w[tagFirst tagSecond])
end
+ it 'uploads avatar for project a project' do
+ project = attributes_for(:project, avatar: fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif'))
+
+ 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")
+ end
+
it 'sets a project as allowing merge even if build fails' do
project = attributes_for(:project, { only_allow_merge_if_pipeline_succeeds: false })
post api('/projects', user), project
@@ -467,8 +476,9 @@ describe API::Projects do
end
describe 'POST /projects/user/:id' do
- before { project }
- before { admin }
+ before do
+ expect(project).to be_persisted
+ end
it 'creates new project without path but with name and return 201' do
expect { post api("/projects/user/#{user.id}", admin), name: 'Foo Project' }.to change {Project.count}.by(1)
@@ -572,7 +582,9 @@ describe API::Projects do
end
describe "POST /projects/:id/uploads" do
- before { project }
+ before do
+ project
+ end
it "uploads the file and returns its info" do
post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")
@@ -720,7 +732,9 @@ describe API::Projects do
describe 'permissions' do
context 'all projects' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'contains permission information' do
get api("/projects", user)
@@ -747,7 +761,9 @@ describe API::Projects do
context 'group project' do
let(:project2) { create(:empty_project, group: create(:group)) }
- before { project2.group.add_owner(user) }
+ before do
+ project2.group.add_owner(user)
+ end
it 'sets the owner and return 200' do
get api("/projects/#{project2.id}", user)
@@ -813,7 +829,9 @@ describe API::Projects do
end
describe 'GET /projects/:id/snippets' do
- before { snippet }
+ before do
+ snippet
+ end
it 'returns an array of project snippets' do
get api("/projects/#{project.id}/snippets", user)
@@ -870,7 +888,9 @@ describe API::Projects do
end
describe 'DELETE /projects/:id/snippets/:snippet_id' do
- before { snippet }
+ before do
+ snippet
+ end
it 'deletes existing project snippet' do
expect do
@@ -1065,14 +1085,16 @@ describe API::Projects do
end
describe 'PUT /projects/:id' do
- before { project }
- before { user }
- before { user3 }
- before { user4 }
- before { project3 }
- before { project4 }
- before { project_member2 }
- before { project_member }
+ before do
+ expect(project).to be_persisted
+ expect(user).to be_persisted
+ expect(user3).to be_persisted
+ expect(user4).to be_persisted
+ expect(project3).to be_persisted
+ expect(project4).to be_persisted
+ expect(project_member2).to be_persisted
+ expect(project_member).to be_persisted
+ end
it 'returns 400 when nothing sent' do
project_param = {}
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index be83514ed9c..d554c242916 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -190,17 +190,23 @@ describe API::Runner do
pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, commands: "ls\ndate")
end
- before { project.runners << runner }
+ before do
+ project.runners << runner
+ end
describe 'POST /api/v4/jobs/request' do
let!(:last_update) {}
let!(:new_update) { }
let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' }
- before { stub_container_registry_config(enabled: false) }
+ before do
+ stub_container_registry_config(enabled: false)
+ end
shared_examples 'no jobs available' do
- before { request_job }
+ before do
+ request_job
+ end
context 'when runner sends version in User-Agent' do
context 'for stable version' do
@@ -277,7 +283,9 @@ describe API::Runner do
end
context 'when jobs are finished' do
- before { job.success }
+ before do
+ job.success
+ end
it_behaves_like 'no jobs available'
end
@@ -356,8 +364,11 @@ describe API::Runner do
expect(json_response['token']).to eq(job.token)
expect(json_response['job_info']).to eq(expected_job_info)
expect(json_response['git_info']).to eq(expected_git_info)
- expect(json_response['image']).to eq({ 'name' => 'ruby:2.1' })
- expect(json_response['services']).to eq([{ 'name' => 'postgres' }])
+ expect(json_response['image']).to eq({ 'name' => 'ruby:2.1', 'entrypoint' => '/bin/sh' })
+ expect(json_response['services']).to eq([{ 'name' => 'postgres', 'entrypoint' => nil,
+ 'alias' => nil, 'command' => nil },
+ { 'name' => 'docker:dind', 'entrypoint' => '/bin/sh',
+ 'alias' => 'docker', 'command' => 'sleep 30' }])
expect(json_response['steps']).to eq(expected_steps)
expect(json_response['artifacts']).to eq(expected_artifacts)
expect(json_response['cache']).to eq(expected_cache)
@@ -431,8 +442,29 @@ describe API::Runner do
expect(response).to have_http_status(201)
expect(json_response['id']).to eq(test_job.id)
expect(json_response['dependencies'].count).to eq(2)
- expect(json_response['dependencies']).to include({ 'id' => job.id, 'name' => job.name, 'token' => job.token },
- { 'id' => job2.id, 'name' => job2.name, 'token' => job2.token })
+ expect(json_response['dependencies']).to include(
+ { 'id' => job.id, 'name' => job.name, 'token' => job.token },
+ { 'id' => job2.id, 'name' => job2.name, 'token' => job2.token })
+ end
+ end
+
+ context 'when pipeline have jobs with artifacts' do
+ let!(:job) { create(:ci_build_tag, :artifacts, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
+ let!(:test_job) { create(:ci_build, pipeline: pipeline, name: 'deploy', stage: 'deploy', stage_idx: 1) }
+
+ before do
+ job.success
+ end
+
+ it 'returns dependent jobs' do
+ request_job
+
+ expect(response).to have_http_status(201)
+ expect(json_response['id']).to eq(test_job.id)
+ expect(json_response['dependencies'].count).to eq(1)
+ expect(json_response['dependencies']).to include(
+ { 'id' => job.id, 'name' => job.name, 'token' => job.token,
+ 'artifacts_file' => { 'filename' => 'ci_build_artifacts.zip', 'size' => 106365 } })
end
end
@@ -484,10 +516,14 @@ describe API::Runner do
end
context 'when job has no tags' do
- before { job.update(tags: []) }
+ before do
+ job.update(tags: [])
+ end
context 'when runner is allowed to pick untagged jobs' do
- before { runner.update_column(:run_untagged, true) }
+ before do
+ runner.update_column(:run_untagged, true)
+ end
it 'picks job' do
request_job
@@ -497,7 +533,9 @@ describe API::Runner do
end
context 'when runner is not allowed to pick untagged jobs' do
- before { runner.update_column(:run_untagged, false) }
+ before do
+ runner.update_column(:run_untagged, false)
+ end
it_behaves_like 'no jobs available'
end
@@ -537,7 +575,9 @@ describe API::Runner do
end
context 'when registry is enabled' do
- before { stub_container_registry_config(enabled: true, host_port: registry_url) }
+ before do
+ stub_container_registry_config(enabled: true, host_port: registry_url)
+ end
it 'sends registry credentials key' do
request_job
@@ -548,7 +588,9 @@ describe API::Runner do
end
context 'when registry is disabled' do
- before { stub_container_registry_config(enabled: false, host_port: registry_url) }
+ before do
+ stub_container_registry_config(enabled: false, host_port: registry_url)
+ end
it 'does not send registry credentials' do
request_job
@@ -570,7 +612,9 @@ describe API::Runner do
describe 'PUT /api/v4/jobs/:id' do
let(:job) { create(:ci_build, :pending, :trace, pipeline: pipeline, runner_id: runner.id) }
- before { job.run! }
+ before do
+ job.run!
+ end
context 'when status is given' do
it 'mark job as succeeded' do
@@ -625,7 +669,9 @@ describe API::Runner do
let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) }
let(:update_interval) { 10.seconds.to_i }
- before { initial_patch_the_trace }
+ before do
+ initial_patch_the_trace
+ end
context 'when request is valid' do
it 'gets correct response' do
@@ -767,7 +813,9 @@ describe API::Runner do
let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') }
- before { job.run! }
+ before do
+ job.run!
+ end
describe 'POST /api/v4/jobs/:id/artifacts/authorize' do
context 'when using token as parameter' do
@@ -873,13 +921,17 @@ describe API::Runner do
end
context 'when uses regular file post' do
- before { upload_artifacts(file_upload, headers_with_token, false) }
+ before do
+ upload_artifacts(file_upload, headers_with_token, false)
+ end
it_behaves_like 'successful artifacts upload'
end
context 'when uses accelerated file post' do
- before { upload_artifacts(file_upload, headers_with_token, true) }
+ before do
+ upload_artifacts(file_upload, headers_with_token, true)
+ end
it_behaves_like 'successful artifacts upload'
end
@@ -1033,7 +1085,9 @@ describe API::Runner do
allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return(@tmpdir)
end
- after { FileUtils.remove_entry @tmpdir }
+ after do
+ FileUtils.remove_entry @tmpdir
+ end
it' "fails to post artifacts for outside of tmp path"' do
upload_artifacts(file_upload, headers_with_token)
@@ -1055,7 +1109,9 @@ describe API::Runner do
describe 'GET /api/v4/jobs/:id/artifacts' do
let(:token) { job.token }
- before { download_artifact }
+ before do
+ download_artifact
+ end
context 'when job has artifacts' do
let(:job) { create(:ci_build, :artifacts) }
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 2398ae6219c..ede48b1c888 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -40,7 +40,10 @@ describe API::Settings, 'Settings' do
plantuml_url: 'http://plantuml.example.com',
default_snippet_visibility: 'internal',
restricted_visibility_levels: ['public'],
- default_artifacts_expire_in: '2 days'
+ default_artifacts_expire_in: '2 days',
+ help_page_text: 'custom help text',
+ help_page_hide_commercial_content: true,
+ 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
@@ -53,6 +56,9 @@ describe API::Settings, 'Settings' do
expect(json_response['default_snippet_visibility']).to eq('internal')
expect(json_response['restricted_visibility_levels']).to eq(['public'])
expect(json_response['default_artifacts_expire_in']).to eq('2 days')
+ expect(json_response['help_page_text']).to eq('custom help text')
+ expect(json_response['help_page_hide_commercial_content']).to be_truthy
+ expect(json_response['help_page_support_url']).to eq('http://example.com/help')
end
end
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index e429cddcf6a..8741cbd4e80 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -80,11 +80,33 @@ describe API::Snippets do
end
end
+ describe 'GET /snippets/:id' do
+ let(:snippet) { create(:personal_snippet, author: user) }
+
+ it 'returns snippet json' do
+ get api("/snippets/#{snippet.id}", user)
+
+ expect(response).to have_http_status(200)
+
+ expect(json_response['title']).to eq(snippet.title)
+ expect(json_response['description']).to eq(snippet.description)
+ expect(json_response['file_name']).to eq(snippet.file_name)
+ end
+
+ it 'returns 404 for invalid snippet id' do
+ get api("/snippets/1234", user)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Not found')
+ end
+ end
+
describe 'POST /snippets/' do
let(:params) do
{
title: 'Test Title',
file_name: 'test.rb',
+ description: 'test description',
content: 'puts "hello world"',
visibility: 'public'
}
@@ -97,6 +119,7 @@ describe API::Snippets do
expect(response).to have_http_status(201)
expect(json_response['title']).to eq(params[:title])
+ expect(json_response['description']).to eq(params[:description])
expect(json_response['file_name']).to eq(params[:file_name])
end
@@ -150,12 +173,14 @@ describe API::Snippets do
it 'updates snippet' do
new_content = 'New content'
+ new_description = 'New description'
- put api("/snippets/#{snippet.id}", user), content: new_content
+ put api("/snippets/#{snippet.id}", user), content: new_content, description: new_description
expect(response).to have_http_status(200)
snippet.reload
expect(snippet.content).to eq(new_content)
+ expect(snippet.description).to eq(new_description)
end
it 'returns 404 for invalid snippet id' do
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 2eb191d6049..f65b475fe44 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -5,7 +5,9 @@ describe API::SystemHooks do
let(:admin) { create(:admin) }
let!(:hook) { create(:system_hook, url: "http://example.com") }
- before { stub_request(:post, hook.url) }
+ before do
+ stub_request(:post, hook.url)
+ end
describe "GET /hooks" do
context "when no user" do
diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb
index cb55985e3f5..f8af9295842 100644
--- a/spec/requests/api/templates_spec.rb
+++ b/spec/requests/api/templates_spec.rb
@@ -2,14 +2,18 @@ require 'spec_helper'
describe API::Templates do
context 'the Template Entity' do
- before { get api('/templates/gitignores/Ruby') }
+ before do
+ get api('/templates/gitignores/Ruby')
+ end
it { expect(json_response['name']).to eq('Ruby') }
it { expect(json_response['content']).to include('*.gem') }
end
context 'the TemplateList Entity' do
- before { get api('/templates/gitignores') }
+ before do
+ get api('/templates/gitignores')
+ end
it { expect(json_response.first['name']).not_to be_nil }
it { expect(json_response.first['content']).to be_nil }
@@ -47,7 +51,9 @@ describe API::Templates do
end
context 'the License Template Entity' do
- before { get api('/templates/licenses/mit') }
+ before do
+ get api('/templates/licenses/mit')
+ end
it 'returns a license template' do
expect(json_response['key']).to eq('mit')
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index ec51b96c86b..9dc4b6972a6 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -160,7 +160,9 @@ describe API::Users do
end
describe "POST /users" do
- before { admin }
+ before do
+ admin
+ end
it "creates user" do
expect do
@@ -349,7 +351,9 @@ describe API::Users do
describe "PUT /users/:id" do
let!(:admin_user) { create(:admin) }
- before { admin }
+ before do
+ admin
+ end
it "updates user with new bio" do
put api("/users/#{user.id}", admin), { bio: 'new test bio' }
@@ -502,7 +506,9 @@ describe API::Users do
end
describe "POST /users/:id/keys" do
- before { admin }
+ before do
+ admin
+ end
it "does not create invalid ssh key" do
post api("/users/#{user.id}/keys", admin), { title: "invalid key" }
@@ -532,7 +538,9 @@ describe API::Users do
end
describe 'GET /user/:id/keys' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -563,7 +571,9 @@ describe API::Users do
end
describe 'DELETE /user/:id/keys/:key_id' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -601,7 +611,9 @@ describe API::Users do
end
describe "POST /users/:id/emails" do
- before { admin }
+ before do
+ admin
+ end
it "does not create invalid email" do
post api("/users/#{user.id}/emails", admin), {}
@@ -625,7 +637,9 @@ describe API::Users do
end
describe 'GET /user/:id/emails' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -662,7 +676,9 @@ describe API::Users do
end
describe 'DELETE /user/:id/emails/:email_id' do
- before { admin }
+ before do
+ admin
+ end
context 'when unauthenticated' do
it 'returns authentication error' do
@@ -708,7 +724,10 @@ describe API::Users do
describe "DELETE /users/:id" do
let!(:namespace) { user.namespace }
let!(:issue) { create(:issue, author: user) }
- before { admin }
+
+ before do
+ admin
+ end
it "deletes user" do
Sidekiq::Testing.inline! { delete api("/users/#{user.id}", admin) }
@@ -1068,7 +1087,10 @@ describe API::Users do
end
describe 'POST /users/:id/block' do
- before { admin }
+ before do
+ admin
+ end
+
it 'blocks existing user' do
post api("/users/#{user.id}/block", admin)
expect(response).to have_http_status(201)
@@ -1096,7 +1118,10 @@ describe API::Users do
describe 'POST /users/:id/unblock' do
let(:blocked_user) { create(:user, state: 'blocked') }
- before { admin }
+
+ before do
+ admin
+ end
it 'unblocks existing user' do
post api("/users/#{user.id}/unblock", admin)
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 286de277ae7..83c675792f4 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -137,6 +137,18 @@ describe Ci::API::Builds do
end
end
end
+
+ context 'when docker configuration options are used' do
+ let!(:build) { create(:ci_build, :extended_options, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
+
+ it 'starts a build' do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response['options']['image']).to eq('ruby:2.1')
+ expect(json_response['options']['services']).to eq(['postgres', 'docker:dind'])
+ end
+ end
end
context 'when builds are finished' do
@@ -229,7 +241,9 @@ describe Ci::API::Builds do
end
context 'when runner is allowed to pick untagged builds' do
- before { runner.update_column(:run_untagged, true) }
+ before do
+ runner.update_column(:run_untagged, true)
+ end
it 'picks build' do
register_builds
@@ -455,7 +469,9 @@ describe Ci::API::Builds do
let(:token) { build.token }
let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => token) }
- before { build.run! }
+ before do
+ build.run!
+ end
describe "POST /builds/:id/artifacts/authorize" do
context "authorizes posting artifact to running build" do
@@ -511,7 +527,9 @@ describe Ci::API::Builds do
end
context 'authorization token is invalid' do
- before { post authorize_url, { token: 'invalid', filesize: 100 } }
+ before do
+ post authorize_url, { token: 'invalid', filesize: 100 }
+ end
it 'responds with forbidden' do
expect(response).to have_http_status(403)
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 0b9733221d8..78b2be350cd 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -12,7 +12,9 @@ describe Ci::API::Runners do
describe "POST /runners/register" do
context 'when runner token is provided' do
- before { post ci_api("/runners/register"), token: registration_token }
+ before do
+ post ci_api("/runners/register"), token: registration_token
+ end
it 'creates runner with default values' do
expect(response).to have_http_status 201
@@ -69,7 +71,10 @@ describe Ci::API::Runners do
context 'when project token is provided' do
let(:project) { FactoryGirl.create(:empty_project) }
- before { post ci_api("/runners/register"), token: project.runners_token }
+
+ before do
+ post ci_api("/runners/register"), token: project.runners_token
+ end
it 'creates runner' do
expect(response).to have_http_status 201
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index f018b48ceb2..dce78faefc9 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -418,17 +418,17 @@ describe 'Git HTTP requests', lib: true do
end
context 'when username and password are provided' do
- it 'rejects pulls with 2FA error message' do
+ it 'rejects pulls with personal access token error message' do
download(path, user: user.username, password: user.password) do |response|
expect(response).to have_http_status(:unauthorized)
- expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP')
+ expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
end
end
- it 'rejects the push attempt' do
+ it 'rejects the push attempt with personal access token error message' do
upload(path, user: user.username, password: user.password) do |response|
expect(response).to have_http_status(:unauthorized)
- expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP')
+ expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
end
end
end
@@ -441,6 +441,41 @@ describe 'Git HTTP requests', lib: true do
end
end
+ context 'when internal auth is disabled' do
+ before do
+ allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false }
+ end
+
+ it 'rejects pulls with personal access token error message' do
+ download(path, user: 'foo', password: 'bar') do |response|
+ expect(response).to have_http_status(:unauthorized)
+ expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
+ end
+ end
+
+ it 'rejects pushes with personal access token error message' do
+ upload(path, user: 'foo', password: 'bar') do |response|
+ expect(response).to have_http_status(:unauthorized)
+ expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
+ end
+ end
+
+ context 'when LDAP is configured' do
+ before do
+ allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
+ allow_any_instance_of(Gitlab::LDAP::Authentication).
+ to receive(:login).and_return(nil)
+ end
+
+ it 'does not display the personal access token error message' do
+ upload(path, user: 'foo', password: 'bar') do |response|
+ expect(response).to have_http_status(:unauthorized)
+ expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP')
+ end
+ end
+ end
+ end
+
context "when blank password attempts follow a valid login" do
def attempt_login(include_password)
password = include_password ? user.password : ""
@@ -592,7 +627,9 @@ describe 'Git HTTP requests', lib: true do
let(:path) { "/#{project.path_with_namespace}/info/refs" }
context "when no params are added" do
- before { get path }
+ before do
+ get path
+ end
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs")
@@ -601,7 +638,10 @@ describe 'Git HTTP requests', lib: true do
context "when the upload-pack service is requested" do
let(:params) { { service: 'git-upload-pack' } }
- before { get path, params }
+
+ before do
+ get path, params
+ end
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
@@ -610,7 +650,10 @@ describe 'Git HTTP requests', lib: true do
context "when the receive-pack service is requested" do
let(:params) { { service: 'git-receive-pack' } }
- before { get path, params }
+
+ before do
+ get path, params
+ end
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
@@ -619,7 +662,10 @@ describe 'Git HTTP requests', lib: true do
context "when the params are anything else" do
let(:params) { { service: 'git-implode-pack' } }
- before { get path, params }
+
+ before do
+ get path, params
+ end
it "redirects to the sign-in page" do
expect(response).to redirect_to(new_user_session_path)
@@ -648,7 +694,7 @@ describe 'Git HTTP requests', lib: true do
# Provide a dummy file in its place
allow_any_instance_of(Repository).to receive(:blob_at).and_call_original
allow_any_instance_of(Repository).to receive(:blob_at).with('b83d6e391c22777fca1ed3012fce84f633d7fed0', 'info/refs') do
- Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt')
+ Blob.decorate(Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt'), project)
end
get "/#{project.path_with_namespace}/blob/master/info/refs"
@@ -660,7 +706,9 @@ describe 'Git HTTP requests', lib: true do
end
context "when the file does not exist" do
- before { get "/#{project.path_with_namespace}/blob/master/info/refs" }
+ before do
+ get "/#{project.path_with_namespace}/blob/master/info/refs"
+ end
it "returns not found" do
expect(response).to have_http_status(:not_found)
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index a3e7844b2f3..5e4cf05748e 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -6,7 +6,9 @@ describe JwtController do
let(:service_name) { 'test' }
let(:parameters) { { service: service_name } }
- before { stub_const('JwtController::SERVICES', service_name => service_class) }
+ before do
+ stub_const('JwtController::SERVICES', service_name => service_class)
+ end
context 'existing service' do
subject! { get '/jwt/auth', parameters }
@@ -41,6 +43,19 @@ describe JwtController do
it { expect(response).to have_http_status(401) }
end
+
+ context 'using personal access tokens' do
+ let(:user) { create(:user) }
+ let(:pat) { create(:personal_access_token, user: user, scopes: ['read_registry']) }
+ let(:headers) { { authorization: credentials('personal_access_token', pat.token) } }
+
+ subject! { get '/jwt/auth', parameters, headers }
+
+ it 'authenticates correctly' do
+ expect(response).to have_http_status(200)
+ expect(service_class).to have_received(:new).with(nil, user, parameters)
+ end
+ end
end
context 'using User login' do
@@ -57,7 +72,7 @@ describe JwtController do
context 'without personal token' do
it 'rejects the authorization attempt' do
expect(response).to have_http_status(401)
- expect(response.body).to include('You have 2FA enabled, please use a personal access token for Git over HTTP')
+ expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
end
end
@@ -75,9 +90,24 @@ describe JwtController do
context 'using invalid login' do
let(:headers) { { authorization: credentials('invalid', 'password') } }
- subject! { get '/jwt/auth', parameters, headers }
+ context 'when internal auth is enabled' do
+ it 'rejects the authorization attempt' do
+ get '/jwt/auth', parameters, headers
+
+ expect(response).to have_http_status(401)
+ expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP')
+ end
+ end
- it { expect(response).to have_http_status(401) }
+ 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 }
+ get '/jwt/auth', parameters, headers
+
+ expect(response).to have_http_status(401)
+ expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
+ end
+ end
end
end
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 05176c3beaa..6d1f0b24196 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/user/avatar/#{user.id}/dk.png"
+ 'picture' => "http://localhost/uploads/system/user/avatar/#{user.id}/dk.png"
})
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 54417f6b3e1..95d40138fea 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -93,13 +93,17 @@ describe 'project routing' do
end
context 'name with dot' do
- before { allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq.keys', any_args).and_return(true) }
+ before do
+ allow(Project).to receive(:find_by_full_path).with('gitlab/gitlabhq.keys', any_args).and_return(true)
+ end
it { expect(get('/gitlab/gitlabhq.keys')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq.keys') }
end
context 'with nested group' do
- before { allow(Project).to receive(:find_by_full_path).with('gitlab/subgroup/gitlabhq', any_args).and_return(true) }
+ before do
+ allow(Project).to receive(:find_by_full_path).with('gitlab/subgroup/gitlabhq', any_args).and_return(true)
+ end
it { expect(get('/gitlab/subgroup/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab/subgroup', id: 'gitlabhq') }
end
@@ -201,10 +205,12 @@ describe 'project routing' do
# POST /:project_id/deploy_keys(.:format) deploy_keys#create
# new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new
# project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show
+ # edit_project_deploy_key GET /:project_id/deploy_keys/:id/edit(.:format) deploy_keys#edit
+ # project_deploy_key PATCH /:project_id/deploy_keys/:id(.:format) deploy_keys#update
# DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy
describe Projects::DeployKeysController, 'routing' do
it_behaves_like 'RESTful project resources' do
- let(:actions) { [:index, :new, :create] }
+ let(:actions) { [:index, :new, :create, :edit, :update] }
let(:controller) { 'deploy_keys' }
end
end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index a62af13cf0c..a45839b16f5 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -286,7 +286,9 @@ end
describe "Groups", "routing" do
let(:name) { 'complex.group-namegit' }
- before { allow_any_instance_of(GroupUrlConstrainer).to receive(:matches?).and_return(true) }
+ before do
+ allow_any_instance_of(GroupUrlConstrainer).to receive(:matches?).and_return(true)
+ end
it "to #show" do
expect(get("/groups/#{name}")).to route_to('groups#show', id: name)
diff --git a/spec/rubocop/cop/activerecord_serialize_spec.rb b/spec/rubocop/cop/activerecord_serialize_spec.rb
index a303b16d264..5bd7e5fa926 100644
--- a/spec/rubocop/cop/activerecord_serialize_spec.rb
+++ b/spec/rubocop/cop/activerecord_serialize_spec.rb
@@ -10,7 +10,7 @@ describe RuboCop::Cop::ActiverecordSerialize do
context 'inside the app/models directory' do
it 'registers an offense when serialize is used' do
- allow(cop).to receive(:in_models?).and_return(true)
+ allow(cop).to receive(:in_model?).and_return(true)
inspect_source(cop, 'serialize :foo')
@@ -23,7 +23,7 @@ describe RuboCop::Cop::ActiverecordSerialize do
context 'outside the app/models directory' do
it 'does nothing' do
- allow(cop).to receive(:in_models?).and_return(false)
+ allow(cop).to receive(:in_model?).and_return(false)
inspect_source(cop, 'serialize :foo')
diff --git a/spec/rubocop/cop/migration/add_timestamps_spec.rb b/spec/rubocop/cop/migration/add_timestamps_spec.rb
new file mode 100644
index 00000000000..18df62dec3e
--- /dev/null
+++ b/spec/rubocop/cop/migration/add_timestamps_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/add_timestamps'
+
+describe RuboCop::Cop::Migration::AddTimestamps do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+ let(:migration_with_add_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_timestamps(:users)
+ end
+ end
+ )
+ end
+
+ let(:migration_without_add_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ end
+ end
+ )
+ end
+
+ let(:migration_with_add_timestamps_with_timezone) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_timestamps_with_timezone(:users)
+ end
+ end
+ )
+ end
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when the "add_timestamps" method is used' do
+ inspect_source(cop, migration_with_add_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([7])
+ end
+ end
+
+ it 'does not register an offense when the "add_timestamps" method is not used' do
+ inspect_source(cop, migration_without_add_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ it 'does not register an offense when the "add_timestamps_with_timezone" method is used' do
+ inspect_source(cop, migration_with_add_timestamps_with_timezone)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, migration_with_add_timestamps)
+ inspect_source(cop, migration_without_add_timestamps)
+ inspect_source(cop, migration_with_add_timestamps_with_timezone)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/datetime_spec.rb b/spec/rubocop/cop/migration/datetime_spec.rb
new file mode 100644
index 00000000000..388b086ce6a
--- /dev/null
+++ b/spec/rubocop/cop/migration/datetime_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/datetime'
+
+describe RuboCop::Cop::Migration::Datetime do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+ let(:migration_with_datetime) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_column(:users, :last_sign_in, :datetime)
+ end
+ end
+ )
+ end
+
+ let(:migration_without_datetime) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ end
+ end
+ )
+ end
+
+ let(:migration_with_datetime_with_timezone) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ add_column(:users, :username, :text)
+ add_column(:users, :last_sign_in, :datetime_with_timezone)
+ end
+ end
+ )
+ end
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when the ":datetime" data type is used' do
+ inspect_source(cop, migration_with_datetime)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([7])
+ end
+ end
+
+ it 'does not register an offense when the ":datetime" data type is not used' do
+ inspect_source(cop, migration_without_datetime)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ it 'does not register an offense when the ":datetime_with_timezone" data type is used' do
+ inspect_source(cop, migration_with_datetime_with_timezone)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, migration_with_datetime)
+ inspect_source(cop, migration_without_datetime)
+ inspect_source(cop, migration_with_datetime_with_timezone)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/timestamps_spec.rb b/spec/rubocop/cop/migration/timestamps_spec.rb
new file mode 100644
index 00000000000..cdf1423d0c5
--- /dev/null
+++ b/spec/rubocop/cop/migration/timestamps_spec.rb
@@ -0,0 +1,99 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/timestamps'
+
+describe RuboCop::Cop::Migration::Timestamps do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+ let(:migration_with_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.timestamps null: true
+ t.string :password
+ end
+ end
+ end
+ )
+ end
+
+ let(:migration_without_timestamps) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.string :password
+ end
+ end
+ end
+ )
+ end
+
+ let(:migration_with_timestamps_with_timezone) do
+ %q(
+ class Users < ActiveRecord::Migration
+ DOWNTIME = false
+
+ def change
+ create_table :users do |t|
+ t.string :username, null: false
+ t.timestamps_with_timezone null: true
+ t.string :password
+ end
+ end
+ end
+ )
+ end
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ it 'registers an offense when the "timestamps" method is used' do
+ inspect_source(cop, migration_with_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([8])
+ end
+ end
+
+ it 'does not register an offense when the "timestamps" method is not used' do
+ inspect_source(cop, migration_without_timestamps)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+
+ it 'does not register an offense when the "timestamps_with_timezone" method is used' do
+ inspect_source(cop, migration_with_timestamps_with_timezone)
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ inspect_source(cop, migration_with_timestamps)
+ inspect_source(cop, migration_without_timestamps)
+ inspect_source(cop, migration_with_timestamps_with_timezone)
+
+ expect(cop.offenses.size).to eq(0)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/polymorphic_associations_spec.rb b/spec/rubocop/cop/polymorphic_associations_spec.rb
new file mode 100644
index 00000000000..49959aa6419
--- /dev/null
+++ b/spec/rubocop/cop/polymorphic_associations_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../rubocop/cop/polymorphic_associations'
+
+describe RuboCop::Cop::PolymorphicAssociations do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'inside the app/models directory' do
+ it 'registers an offense when polymorphic: true is used' do
+ allow(cop).to receive(:in_model?).and_return(true)
+
+ inspect_source(cop, 'belongs_to :foo, polymorphic: true')
+
+ 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, polymorphic: true')
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+end
diff --git a/spec/rubocop/cop/rspec/single_line_hook_spec.rb b/spec/rubocop/cop/rspec/single_line_hook_spec.rb
new file mode 100644
index 00000000000..6cf0831d3ad
--- /dev/null
+++ b/spec/rubocop/cop/rspec/single_line_hook_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/rspec/single_line_hook'
+
+describe RuboCop::Cop::RSpec::SingleLineHook do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ # Override `CopHelper#inspect_source` to always appear to be in a spec file,
+ # so that our RSpec-only cop actually runs
+ def inspect_source(*args)
+ super(*args, 'foo_spec.rb')
+ end
+
+ it 'registers an offense for a single-line `before` block' do
+ inspect_source(cop, 'before { do_something }')
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['before { do_something }'])
+ end
+
+ it 'registers an offense for a single-line `after` block' do
+ inspect_source(cop, 'after(:each) { undo_something }')
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['after(:each) { undo_something }'])
+ end
+
+ it 'registers an offense for a single-line `around` block' do
+ inspect_source(cop, 'around { |ex| do_something_else }')
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq(['around { |ex| do_something_else }'])
+ end
+
+ it 'ignores a multi-line `before` block' do
+ inspect_source(cop, ['before do',
+ ' do_something',
+ 'end'])
+
+ expect(cop.offenses.size).to eq(0)
+ end
+
+ it 'ignores a multi-line `after` block' do
+ inspect_source(cop, ['after(:each) do',
+ ' undo_something',
+ 'end'])
+
+ expect(cop.offenses.size).to eq(0)
+ end
+
+ it 'ignores a multi-line `around` block' do
+ inspect_source(cop, ['around do |ex|',
+ ' do_something_else',
+ 'end'])
+
+ expect(cop.offenses.size).to eq(0)
+ end
+end
diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb
index e2511e8968c..b92c1c28ba8 100644
--- a/spec/serializers/build_details_entity_spec.rb
+++ b/spec/serializers/build_details_entity_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe BuildDetailsEntity do
set(:user) { create(:admin) }
- it 'inherits from BuildEntity' do
- expect(described_class).to be < BuildEntity
+ it 'inherits from JobEntity' do
+ expect(described_class).to be < JobEntity
end
describe '#as_json' do
@@ -29,7 +29,7 @@ describe BuildDetailsEntity do
it 'contains the needed key value pairs' do
expect(subject).to include(:coverage, :erased_at, :duration)
- expect(subject).to include(:artifacts, :runner, :pipeline)
+ expect(subject).to include(:runner, :pipeline)
expect(subject).to include(:raw_path, :merge_request)
expect(subject).to include(:new_issue_path)
end
diff --git a/spec/serializers/deploy_key_entity_spec.rb b/spec/serializers/deploy_key_entity_spec.rb
index e73fbe190ca..ed89fccc3d0 100644
--- a/spec/serializers/deploy_key_entity_spec.rb
+++ b/spec/serializers/deploy_key_entity_spec.rb
@@ -12,27 +12,44 @@ describe DeployKeyEntity do
let(:entity) { described_class.new(deploy_key, user: user) }
- it 'returns deploy keys with projects a user can read' do
- expected_result = {
- id: deploy_key.id,
- user_id: deploy_key.user_id,
- title: deploy_key.title,
- fingerprint: deploy_key.fingerprint,
- can_push: deploy_key.can_push,
- destroyed_when_orphaned: true,
- almost_orphaned: false,
- created_at: deploy_key.created_at,
- updated_at: deploy_key.updated_at,
- projects: [
- {
- id: project.id,
- name: project.name,
- full_path: namespace_project_path(project.namespace, project),
- full_name: project.full_name
- }
- ]
- }
-
- expect(entity.as_json).to eq(expected_result)
+ describe 'returns deploy keys with projects a user can read' do
+ let(:expected_result) do
+ {
+ id: deploy_key.id,
+ user_id: deploy_key.user_id,
+ title: deploy_key.title,
+ fingerprint: deploy_key.fingerprint,
+ can_push: deploy_key.can_push,
+ destroyed_when_orphaned: true,
+ almost_orphaned: false,
+ created_at: deploy_key.created_at,
+ updated_at: deploy_key.updated_at,
+ can_edit: false,
+ projects: [
+ {
+ id: project.id,
+ name: project.name,
+ full_path: namespace_project_path(project.namespace, project),
+ full_name: project.full_name
+ }
+ ]
+ }
+ end
+
+ it { expect(entity.as_json).to eq(expected_result) }
+ end
+
+ describe 'returns can_edit true if user is a master of project' do
+ before do
+ project.add_master(user)
+ end
+
+ it { expect(entity.as_json).to include(can_edit: true) }
+ end
+
+ describe 'returns can_edit true if a user admin' do
+ let(:user) { create(:user, :admin) }
+
+ it { expect(entity.as_json).to include(can_edit: true) }
end
end
diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb
index d2ad6c44702..4c52a00b442 100644
--- a/spec/serializers/environment_serializer_spec.rb
+++ b/spec/serializers/environment_serializer_spec.rb
@@ -62,7 +62,9 @@ describe EnvironmentSerializer do
subject { serializer.represent(resource) }
context 'when there is a single environment' do
- before { create(:environment, name: 'staging') }
+ before do
+ create(:environment, name: 'staging')
+ end
it 'represents one standalone environment' do
expect(subject.count).to eq 1
@@ -138,7 +140,9 @@ describe EnvironmentSerializer do
context 'when resource is paginatable relation' do
context 'when there is a single environment object in relation' do
- before { create(:environment) }
+ before do
+ create(:environment)
+ end
it 'serializes environments' do
expect(subject.first).to have_key :id
@@ -146,7 +150,9 @@ describe EnvironmentSerializer do
end
context 'when multiple environment objects are serialized' do
- before { create_list(:environment, 3) }
+ before do
+ create_list(:environment, 3)
+ end
it 'serializes appropriate number of objects' do
expect(subject.count).to be 2
diff --git a/spec/serializers/build_entity_spec.rb b/spec/serializers/job_entity_spec.rb
index 46d43a80ef7..5ca7bf2fcaf 100644
--- a/spec/serializers/build_entity_spec.rb
+++ b/spec/serializers/job_entity_spec.rb
@@ -1,24 +1,24 @@
require 'spec_helper'
-describe BuildEntity do
+describe JobEntity do
let(:user) { create(:user) }
- let(:build) { create(:ci_build, :failed) }
- let(:project) { build.project }
+ let(:job) { create(:ci_build) }
+ let(:project) { job.project }
let(:request) { double('request') }
before do
allow(request).to receive(:current_user).and_return(user)
+ project.add_developer(user)
end
let(:entity) do
- described_class.new(build, request: request)
+ described_class.new(job, request: request)
end
subject { entity.as_json }
- it 'contains paths to build page and retry action' do
- expect(subject).to include(:build_path, :retry_path)
- expect(subject[:retry_path]).not_to be_nil
+ it 'contains paths to job page action' do
+ expect(subject).to include(:build_path)
end
it 'does not contain sensitive information' do
@@ -27,7 +27,7 @@ describe BuildEntity do
end
it 'contains whether it is playable' do
- expect(subject[:playable]).to eq build.playable?
+ expect(subject[:playable]).to eq job.playable?
end
it 'contains timestamps' do
@@ -39,18 +39,38 @@ describe BuildEntity do
expect(subject[:status]).to include :icon, :favicon, :text, :label
end
- context 'when build is a regular job' do
+ context 'when job is retryable' do
+ before do
+ job.update(status: :failed)
+ end
+
+ it 'contains cancel path' do
+ expect(subject).to include(:retry_path)
+ end
+ end
+
+ context 'when job is cancelable' do
+ before do
+ job.update(status: :running)
+ end
+
+ it 'contains cancel path' do
+ expect(subject).to include(:cancel_path)
+ end
+ end
+
+ context 'when job is a regular job' do
it 'does not contain path to play action' do
expect(subject).not_to include(:play_path)
end
- it 'is not a playable job' do
+ it 'is not a playable build' do
expect(subject[:playable]).to be false
end
end
- context 'when build is a manual action' do
- let(:build) { create(:ci_build, :manual) }
+ context 'when job is a manual action' do
+ let(:job) { create(:ci_build, :manual) }
context 'when user is allowed to trigger action' do
before do
@@ -79,4 +99,25 @@ describe BuildEntity do
end
end
end
+
+ context 'when job is generic commit status' do
+ let(:job) { create(:generic_commit_status, target_url: 'http://google.com') }
+
+ it 'contains paths to target action' do
+ expect(subject).to include(:build_path)
+ end
+
+ it 'does not contain paths to other action paths' do
+ expect(subject).not_to include(:retry_path, :cancel_path, :play_path)
+ end
+
+ it 'contains timestamps' do
+ expect(subject).to include(:created_at, :updated_at)
+ end
+
+ it 'contains details' do
+ expect(subject).to include :status
+ expect(subject[:status]).to include :icon, :favicon, :text, :label
+ end
+ end
end
diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb
index 03cc5ae9b63..d28dec9592a 100644
--- a/spec/serializers/pipeline_details_entity_spec.rb
+++ b/spec/serializers/pipeline_details_entity_spec.rb
@@ -51,7 +51,9 @@ describe PipelineDetailsEntity do
end
context 'user has ability to retry pipeline' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'retryable flag is true' do
expect(subject[:flags][:retryable]).to eq true
@@ -77,7 +79,9 @@ describe PipelineDetailsEntity do
end
context 'user has ability to cancel pipeline' do
- before { project.add_developer(user) }
+ before do
+ project.add_developer(user)
+ end
it 'cancelable flag is true' do
expect(subject[:flags][:cancelable]).to eq true
@@ -91,6 +95,20 @@ describe PipelineDetailsEntity do
end
end
+ context 'when pipeline has commit statuses' do
+ let(:pipeline) { create(:ci_empty_pipeline) }
+
+ before do
+ create(:generic_commit_status, pipeline: pipeline)
+ end
+
+ it 'contains stages' do
+ expect(subject).to include(:details)
+ expect(subject[:details]).to include(:stages)
+ expect(subject[:details][:stages].first).to include(name: 'external')
+ end
+ end
+
context 'when pipeline has YAML errors' do
let(:pipeline) do
create(:ci_pipeline, config: { rspec: { invalid: :value } })
diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb
index a059c2cc736..46650f3a80d 100644
--- a/spec/serializers/pipeline_entity_spec.rb
+++ b/spec/serializers/pipeline_entity_spec.rb
@@ -51,7 +51,9 @@ describe PipelineEntity do
end
context 'user has ability to retry pipeline' do
- before { project.team << [user, :developer] }
+ before do
+ project.team << [user, :developer]
+ end
it 'contains retry path' do
expect(subject[:retry_path]).to be_present
@@ -77,7 +79,9 @@ describe PipelineEntity do
end
context 'user has ability to cancel pipeline' do
- before { project.add_developer(user) }
+ before do
+ project.add_developer(user)
+ end
it 'contains cancel path' do
expect(subject[:cancel_path]).to be_present
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index 088f24eb180..44813656aff 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -69,7 +69,9 @@ describe PipelineSerializer do
let(:pagination) { { page: 1, per_page: 2 } }
context 'when a single pipeline object is present in relation' do
- before { create(:ci_empty_pipeline) }
+ before do
+ create(:ci_empty_pipeline)
+ end
it 'serializes pipeline relation' do
expect(subject.first).to have_key :id
@@ -77,7 +79,9 @@ describe PipelineSerializer do
end
context 'when a multiple pipeline objects are being serialized' do
- before { create_list(:ci_empty_pipeline, 3) }
+ before do
+ create_list(:ci_empty_pipeline, 3)
+ end
it 'serializes appropriate number of objects' do
expect(subject.count).to be 2
@@ -102,18 +106,11 @@ describe PipelineSerializer do
Ci::Pipeline::AVAILABLE_STATUSES.each do |status|
create_pipeline(status)
end
-
- RequestStore.begin!
- end
-
- after do
- RequestStore.end!
- RequestStore.clear!
end
- it "verifies number of queries" do
+ it 'verifies number of queries', :request_store do
recorded = ActiveRecord::QueryRecorder.new { subject }
- expect(recorded.count).to be_within(1).of(60)
+ expect(recorded.count).to be_within(1).of(57)
expect(recorded.cached_count).to eq(0)
end
diff --git a/spec/serializers/stage_entity_spec.rb b/spec/serializers/stage_entity_spec.rb
index 64b3217b809..40e303f7b89 100644
--- a/spec/serializers/stage_entity_spec.rb
+++ b/spec/serializers/stage_entity_spec.rb
@@ -54,6 +54,17 @@ describe StageEntity do
it 'exposes the group key' do
expect(subject).to include :groups
end
+
+ context 'and contains commit status' do
+ before do
+ create(:generic_commit_status, pipeline: pipeline, stage: 'test')
+ end
+
+ it 'contains commit status' do
+ groups = subject[:groups].map { |group| group[:name] }
+ expect(groups).to include('generic')
+ end
+ end
end
end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index e273dfe1552..60cb7a9440f 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -34,7 +34,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for changed configuration' do
- before { stub_application_setting(container_registry_token_expire_delay: expire_delay) }
+ before do
+ stub_application_setting(container_registry_token_expire_delay: expire_delay)
+ end
it { expect(expires_at).to be_within(2.seconds).of(Time.now + expire_delay.minutes) }
end
@@ -117,7 +119,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'allow developer to push images' do
- before { project.team << [current_user, :developer] }
+ before do
+ project.team << [current_user, :developer]
+ end
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push" }
@@ -128,7 +132,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'allow reporter to pull images' do
- before { project.team << [current_user, :reporter] }
+ before do
+ project.team << [current_user, :reporter]
+ end
context 'when pulling from root level repository' do
let(:current_params) do
@@ -141,7 +147,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'return a least of privileges' do
- before { project.team << [current_user, :reporter] }
+ before do
+ project.team << [current_user, :reporter]
+ end
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:push,pull" }
@@ -152,7 +160,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'disallow guest to pull or push images' do
- before { project.team << [current_user, :guest] }
+ before do
+ project.team << [current_user, :guest]
+ end
let(:current_params) do
{ scope: "repository:#{project.path_with_namespace}:pull,push" }
@@ -355,7 +365,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'for project without container registry' do
let(:project) { create(:empty_project, :public, container_registry_enabled: false) }
- before { project.update(container_registry_enabled: false) }
+ before do
+ project.update(container_registry_enabled: false)
+ end
context 'disallow when pulling' do
let(:current_params) do
diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb
index a8555f5b4a0..effa4633d13 100644
--- a/spec/services/boards/create_service_spec.rb
+++ b/spec/services/boards/create_service_spec.rb
@@ -14,8 +14,9 @@ describe Boards::CreateService, services: true do
it 'creates the default lists' do
board = service.execute
- expect(board.lists.size).to eq 1
- expect(board.lists.first).to be_closed
+ expect(board.lists.size).to eq 2
+ expect(board.lists.first).to be_backlog
+ expect(board.lists.last).to be_closed
end
end
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index c982031c791..a1e220c2322 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -13,6 +13,7 @@ describe Boards::Issues::ListService, services: true do
let(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
let(:p3) { create(:label, title: 'P3', project: project, priority: 3) }
+ let!(:backlog) { create(:backlog_list, board: board) }
let!(:list1) { create(:list, board: board, label: development, position: 0) }
let!(:list2) { create(:list, board: board, label: testing, position: 1) }
let!(:closed) { create(:closed_list, board: board) }
@@ -53,12 +54,20 @@ describe Boards::Issues::ListService, services: true do
expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
end
+ it 'returns opened issues when listing issues from Backlog' do
+ params = { board_id: board.id, id: backlog.id }
+
+ issues = described_class.new(project, user, params).execute
+
+ expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
+ end
+
it 'returns closed issues when listing issues from Closed' do
params = { board_id: board.id, id: closed.id }
issues = described_class.new(project, user, params).execute
- expect(issues).to eq [closed_issue4, closed_issue2, closed_issue5, closed_issue3, closed_issue1]
+ expect(issues).to eq [closed_issue4, closed_issue2, 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/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb
index ab9fb1bc914..68140759600 100644
--- a/spec/services/boards/lists/list_service_spec.rb
+++ b/spec/services/boards/lists/list_service_spec.rb
@@ -1,16 +1,33 @@
require 'spec_helper'
describe Boards::Lists::ListService, services: true do
+ let(:project) { create(:empty_project) }
+ let(:board) { create(:board, project: project) }
+ let(:label) { create(:label, project: project) }
+ let!(:list) { create(:list, board: board, label: label) }
+ let(:service) { described_class.new(project, double) }
+
describe '#execute' do
- it "returns board's lists" do
- project = create(:empty_project)
- board = create(:board, project: project)
- label = create(:label, project: project)
- list = create(:list, board: board, label: label)
+ context 'when the board has a backlog list' do
+ let!(:backlog_list) { create(:backlog_list, board: board) }
+
+ it 'does not create a backlog list' do
+ expect { service.execute(board) }.not_to change(board.lists, :count)
+ end
+
+ it "returns board's lists" do
+ expect(service.execute(board)).to eq [backlog_list, list, board.closed_list]
+ end
+ end
- service = described_class.new(project, double)
+ context 'when the board does not have a backlog list' do
+ it 'creates a backlog list' do
+ expect { service.execute(board) }.to change(board.lists, :count).by(1)
+ end
- expect(service.execute(board)).to eq [list, board.closed_list]
+ it "returns board's lists" do
+ expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list]
+ end
end
end
end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 597c3947e71..77c07b71c68 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::CreatePipelineService, services: true do
+describe Ci::CreatePipelineService, :services do
let(:project) { create(:project, :repository) }
let(:user) { create(:admin) }
@@ -30,6 +30,7 @@ describe Ci::CreatePipelineService, services: true do
it 'creates a pipeline' do
expect(pipeline).to be_kind_of(Ci::Pipeline)
expect(pipeline).to be_valid
+ expect(pipeline).to be_persisted
expect(pipeline).to be_push
expect(pipeline).to eq(project.pipelines.last)
expect(pipeline).to have_attributes(user: user)
@@ -37,6 +38,14 @@ describe Ci::CreatePipelineService, services: true do
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
end
+ it 'increments the prometheus counter' do
+ expect(Gitlab::Metrics).to receive(:counter)
+ .with(:pipelines_created_count, "Pipelines created count")
+ .and_call_original
+
+ pipeline
+ end
+
context 'when merge requests already exist for this source branch' do
it 'updates head pipeline of each merge request' do
merge_request_1 = create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project)
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 7254e6b357a..ef9927c5969 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -25,12 +25,24 @@ describe Ci::RetryBuildService, :services do
user_id auto_canceled_by_id retried].freeze
shared_examples 'build duplication' do
+ let(:stage) do
+ # TODO, we still do not have factory for new stages, we will need to
+ # switch existing factory to persist stages, instead of using LegacyStage
+ #
+ Ci::Stage.create!(project: project, pipeline: pipeline, name: 'test')
+ end
+
let(:build) do
create(:ci_build, :failed, :artifacts_expired, :erased,
:queued, :coverage, :tags, :allowed_to_fail, :on_tag,
- :teardown_environment, :triggered, :trace,
- description: 'some build', pipeline: pipeline,
- auto_canceled_by: create(:ci_empty_pipeline))
+ :triggered, :trace, :teardown_environment,
+ description: 'my-job', stage: 'test', pipeline: pipeline,
+ auto_canceled_by: create(:ci_empty_pipeline)) do |build|
+ ##
+ # TODO, workaround for FactoryGirl limitation when having both
+ # stage (text) and stage_id (integer) columns in the table.
+ build.stage_id = stage.id
+ end
end
describe 'clone accessors' do
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index c44e6b2a48b..efefa8e8eca 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -9,7 +9,9 @@ describe Ci::UpdateBuildQueueService, :services do
let(:runner) { create(:ci_runner) }
context 'when there are runner that can pick build' do
- before { build.project.runners << runner }
+ before do
+ build.project.runners << runner
+ end
it 'ticks runner queue value' do
expect { subject.execute(build) }
@@ -36,7 +38,9 @@ describe Ci::UpdateBuildQueueService, :services do
end
context 'when there are no runners that can pick build' do
- before { build.tag_list = [:docker] }
+ before do
+ build.tag_list = [:docker]
+ end
it 'does not tick runner queue value' do
expect { subject.execute(build) }
diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb
index 5398b5c3f7e..6cf4342ad4c 100644
--- a/spec/services/create_deployment_service_spec.rb
+++ b/spec/services/create_deployment_service_spec.rb
@@ -204,7 +204,9 @@ describe CreateDeploymentService, services: true do
let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
context "while updating the 'first_deployed_to_production_at' time" do
- before { merge_request.mark_as_merged }
+ before do
+ merge_request.mark_as_merged
+ end
context "for merge requests merged before the current deploy" do
it "sets the time if the deploy's environment is 'production'" do
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index bcb62429275..fbd9026640c 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -14,7 +14,9 @@ describe Groups::CreateService, '#execute', services: true do
end
context "cannot create group with restricted visibility level" do
- before { allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) }
+ before do
+ allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC])
+ end
it { is_expected.not_to be_persisted }
end
@@ -25,7 +27,9 @@ describe Groups::CreateService, '#execute', services: true do
let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
context 'as group owner' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it { is_expected.to be_persisted }
end
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index 6437d00e451..eb9b1670c71 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -72,7 +72,7 @@ describe Issuable::BulkUpdateService, services: true do
end
context "when the new assignee ID is #{IssuableFinder::NONE}" do
- it "unassigns the issues" do
+ it 'unassigns the issues' do
expect { bulk_update(merge_request, assignee_id: IssuableFinder::NONE) }
.to change { merge_request.reload.assignee }.to(nil)
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index dab1a3469f7..370bd352200 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -155,7 +155,9 @@ describe Issues::CreateService, services: true do
context 'issue create service' do
context 'assignees' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'removes assignee when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_ids: [-1] }
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 9f8346d52bb..d1dd1466d95 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -251,12 +251,18 @@ describe Issues::MoveService, services: true do
end
context 'user is reporter only in new project' do
- before { new_project.team << [user, :reporter] }
+ before do
+ new_project.team << [user, :reporter]
+ end
+
it { expect { move }.to raise_error(StandardError, /permissions/) }
end
context 'user is reporter only in old project' do
- before { old_project.team << [user, :reporter] }
+ before do
+ old_project.team << [user, :reporter]
+ end
+
it { expect { move }.to raise_error(StandardError, /permissions/) }
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 5184c1d5f19..c26642f5015 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -31,6 +31,13 @@ describe Issues::UpdateService, services: true do
end
end
+ def find_notes(action)
+ issue
+ .notes
+ .joins(:system_note_metadata)
+ .where(system_note_metadata: { action: action })
+ end
+
def update_issue(opts)
described_class.new(project, user, opts).execute(issue)
end
@@ -288,7 +295,9 @@ describe Issues::UpdateService, services: true do
end
context 'when issue has the `label` label' do
- before { issue.labels << label }
+ before do
+ issue.labels << label
+ end
it 'does not send notifications for existing labels' do
opts = { label_ids: [label.id, label2.id] }
@@ -322,7 +331,9 @@ describe Issues::UpdateService, services: true do
it { expect(issue.tasks?).to eq(true) }
context 'when tasks are marked as completed' do
- before { update_issue(description: "- [x] Task 1\n- [X] Task 2") }
+ before do
+ update_issue(description: "- [x] Task 1\n- [X] Task 2")
+ end
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
@@ -330,6 +341,9 @@ describe Issues::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
@@ -345,6 +359,9 @@ describe Issues::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
@@ -354,10 +371,12 @@ describe Issues::UpdateService, services: true do
update_issue(description: "- [x] Task 1\n- [ ] Task 3\n- [ ] Task 2")
end
- it 'does not create a system note' do
- note = find_note('marked the task **Task 2** as incomplete')
+ it 'does not create a system note for the task' do
+ task_note = find_note('marked the task **Task 2** as incomplete')
+ description_notes = find_notes('description')
- expect(note).to be_nil
+ expect(task_note).to be_nil
+ expect(description_notes.length).to eq(2)
end
end
@@ -368,9 +387,11 @@ describe Issues::UpdateService, services: true do
end
it 'does not create a system note referencing the position the old item' do
- note = find_note('marked the task **Two** as incomplete')
+ task_note = find_note('marked the task **Two** as incomplete')
+ description_notes = find_notes('description')
- expect(note).to be_nil
+ expect(task_note).to be_nil
+ expect(description_notes.length).to eq(2)
end
it 'does not generate a new note at all' do
@@ -400,7 +421,9 @@ describe Issues::UpdateService, services: true do
context 'when remove_label_ids and label_ids are passed' do
let(:params) { { label_ids: [], remove_label_ids: [label.id] } }
- before { issue.update_attributes(labels: [label, label3]) }
+ before do
+ issue.update_attributes(labels: [label, label3])
+ end
it 'ignores the label_ids parameter' do
expect(result.label_ids).not_to be_empty
@@ -414,7 +437,9 @@ describe Issues::UpdateService, services: true do
context 'when add_label_ids and remove_label_ids are passed' do
let(:params) { { add_label_ids: [label3.id], remove_label_ids: [label.id] } }
- before { issue.update_attributes(labels: [label]) }
+ before do
+ issue.update_attributes(labels: [label])
+ end
it 'adds the passed labels' do
expect(result.label_ids).to include(label3.id)
diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb
index 5ce8e17976b..5a05ab3ea50 100644
--- a/spec/services/members/create_service_spec.rb
+++ b/spec/services/members/create_service_spec.rb
@@ -5,7 +5,9 @@ describe Members::CreateService, services: true do
let(:user) { create(:user) }
let(:project_user) { create(:user) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST }
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 6f9d1208b1d..01ef52396d7 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -206,7 +206,9 @@ describe MergeRequests::BuildService, services: true do
context 'branch starts with external issue IID followed by a hyphen' do
let(:source_branch) { '12345-fix-issue' }
- before { allow(project).to receive(:default_issues_tracker?).and_return(false) }
+ before do
+ allow(project).to receive(:default_issues_tracker?).and_return(false)
+ end
it 'sets the title to: Resolves External Issue $issue-iid' do
expect(merge_request.title).to eq('Resolve External Issue 12345')
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 2963f62cc7d..13fee953e41 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -150,7 +150,9 @@ describe MergeRequests::CreateService, services: true do
context 'asssignee_id' do
let(:assignee) { create(:user) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'removes assignee_id when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_id: -1 }
diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
index 935f4710851..bb46e1dd9ab 100644
--- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
+++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
@@ -10,8 +10,8 @@ describe MergeRequests::MergeRequestDiffCacheService do
expect(Rails.cache).to receive(:read).with(cache_key).and_return({})
expect(Rails.cache).to receive(:write).with(cache_key, anything)
- allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => true))
- allow_any_instance_of(Repository).to receive(:diffable?).and_return(true)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(true)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(true)
subject.execute(merge_request)
end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index d96f819e66a..b3b188a805f 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -81,7 +81,9 @@ describe MergeRequests::MergeService, services: true do
end
context "when jira_issue_transition_id is not present" do
- before { allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil) }
+ before do
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil)
+ end
it "does not close issue" do
allow(jira_tracker).to receive_messages(jira_issue_transition_id: nil)
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index d371fc68312..fd46020bbdb 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -30,6 +30,13 @@ describe MergeRequests::UpdateService, services: true do
end
end
+ def find_notes(action)
+ @merge_request
+ .notes
+ .joins(:system_note_metadata)
+ .where(system_note_metadata: { action: action })
+ end
+
def update_merge_request(opts)
@merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
@merge_request.reload
@@ -349,7 +356,9 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when issue has the `label` label' do
- before { merge_request.labels << label }
+ before do
+ merge_request.labels << label
+ end
it 'does not send notifications for existing labels' do
opts = { label_ids: [label.id, label2.id] }
@@ -381,12 +390,16 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when MergeRequest has tasks' do
- before { update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" }) }
+ before do
+ update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" })
+ end
it { expect(@merge_request.tasks?).to eq(true) }
context 'when tasks are marked as completed' do
- before { update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" }) }
+ before do
+ update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" })
+ end
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
@@ -394,6 +407,9 @@ describe MergeRequests::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
@@ -409,6 +425,9 @@ describe MergeRequests::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
end
diff --git a/spec/services/notes/slash_commands_service_spec.rb b/spec/services/notes/slash_commands_service_spec.rb
index c9954dc3603..d5ffc1908a9 100644
--- a/spec/services/notes/slash_commands_service_spec.rb
+++ b/spec/services/notes/slash_commands_service_spec.rb
@@ -6,7 +6,9 @@ describe Notes::SlashCommandsService, services: true do
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
- before { project.team << [assignee, :master] }
+ before do
+ project.team << [assignee, :master]
+ end
end
shared_examples 'note on noteable that does not support slash commands' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index de3bbc6b6a1..f1e00c1163b 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1539,8 +1539,7 @@ describe NotificationService, services: true do
# When resource is nil it means global notification
def update_custom_notification(event, user, resource: nil, value: true)
setting = user.notification_settings_for(resource)
- setting.events[event] = value
- setting.save
+ setting.update!(event => value)
end
def add_users_with_subscription(project, issuable)
diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb
index aa63fe3a5c1..cf38c7c75e5 100644
--- a/spec/services/pages_service_spec.rb
+++ b/spec/services/pages_service_spec.rb
@@ -10,10 +10,14 @@ describe PagesService, services: true do
end
context 'execute asynchronously for pages job' do
- before { build.name = 'pages' }
+ before do
+ build.name = 'pages'
+ end
context 'on success' do
- before { build.success }
+ before do
+ build.success
+ end
it 'executes worker' do
expect(PagesWorker).to receive(:perform_async)
@@ -23,7 +27,9 @@ describe PagesService, services: true do
%w(pending running failed canceled).each do |status|
context "on #{status}" do
- before { build.status = status }
+ before do
+ build.status = status
+ end
it 'does not execute worker' do
expect(PagesWorker).not_to receive(:perform_async)
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 3c566c04d6b..40298dcb723 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -115,7 +115,7 @@ describe Projects::CreateService, '#execute', services: true do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
opts.merge!(
- visibility_level: Gitlab::VisibilityLevel.options['Public']
+ visibility_level: Gitlab::VisibilityLevel::PUBLIC
)
end
diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb
index 0657b7e93fe..d75851134ee 100644
--- a/spec/services/projects/participants_service_spec.rb
+++ b/spec/services/projects/participants_service_spec.rb
@@ -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/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/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/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index b957517c715..5d2f4cf17fb 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -59,12 +59,16 @@ describe Projects::TransferService, services: true do
context 'visibility level' do
let(:internal_group) { create(:group, :internal) }
- before { internal_group.add_owner(user) }
+ before do
+ internal_group.add_owner(user)
+ end
context 'when namespace visibility level < project visibility level' do
let(:public_project) { create(:project, :public, :repository, namespace: user.namespace) }
- before { transfer_project(public_project, user, internal_group) }
+ before do
+ transfer_project(public_project, user, internal_group)
+ end
it { expect(public_project.visibility_level).to eq(internal_group.visibility_level) }
end
@@ -72,7 +76,9 @@ describe Projects::TransferService, services: true do
context 'when namespace visibility level > project visibility level' do
let(:private_project) { create(:project, :private, :repository, namespace: user.namespace) }
- before { transfer_project(private_project, user, internal_group) }
+ before do
+ transfer_project(private_project, user, internal_group)
+ end
it { expect(private_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) }
end
diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb
index e5e400ee281..c12fb1a6e53 100644
--- a/spec/services/slash_commands/interpret_service_spec.rb
+++ b/spec/services/slash_commands/interpret_service_spec.rb
@@ -378,13 +378,15 @@ describe SlashCommands::InterpretService, services: true do
context 'assign command with multiple assignees' do
let(:content) { "/assign @#{developer.username} @#{developer2.username}" }
- before{ project.team << [developer2, :developer] }
+ before do
+ project.team << [developer2, :developer]
+ end
context 'Issue' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, issue)
- expect(updates[:assignee_ids]).to match_array([developer.id, developer2.id])
+ expect(updates[:assignee_ids]).to match_array([developer.id])
end
end
@@ -798,7 +800,11 @@ describe SlashCommands::InterpretService, services: true do
context 'if the project has multiple boards' do
let(:issuable) { issue }
- before { create(:board, project: project) }
+
+ before do
+ create(:board, project: project)
+ end
+
it_behaves_like 'empty command'
end
diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb
index 74cba8c014b..5e6e43b7a90 100644
--- a/spec/services/spam_service_spec.rb
+++ b/spec/services/spam_service_spec.rb
@@ -70,7 +70,9 @@ describe SpamService, services: true do
end
context 'when not indicated as spam by akismet' do
- before { allow(AkismetService).to receive(:new).and_return(double(is_spam?: false)) }
+ before do
+ allow(AkismetService).to receive(:new).and_return(double(is_spam?: false))
+ end
it 'returns false' do
expect(check_spam(issue, request, false)).to be_falsey
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index c499b1bb343..9295c09aefc 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -1052,7 +1052,7 @@ describe SystemNoteService, services: true do
let(:action) { 'task' }
end
- it "posts the 'marked as a Work In Progress from commit' system note" do
+ it "posts the 'marked the task as complete' system note" do
expect(subject.note).to eq("marked the task **task** as completed")
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 994c7dcbb46..01ac3cbd3f6 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -3,6 +3,7 @@ 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'
@@ -55,6 +56,8 @@ 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 MigrationsHelpers, :migration
config.infer_spec_type_from_file_location!
@@ -72,10 +75,18 @@ RSpec.configure do |config|
TestEnv.cleanup
end
+ config.before(:example, :request_store) do
+ RequestStore.begin!
+ end
+
+ config.after(:example, :request_store) do
+ RequestStore.end!
+ RequestStore.clear!
+ end
+
if ENV['CI']
- # Retry only on feature specs that use JS
- config.around :each, :js do |ex|
- ex.run_with_retry retry: 3
+ config.around(:each) do |ex|
+ ex.run_with_retry retry: 2
end
end
@@ -96,6 +107,15 @@ RSpec.configure do |config|
Sidekiq.redis(&:flushall)
end
+ config.before(:example, :migration) do
+ ActiveRecord::Migrator
+ .migrate(migrations_paths, previous_migration.version)
+ end
+
+ config.after(:example, :migration) do
+ ActiveRecord::Migrator.migrate(migrations_paths)
+ end
+
config.around(:each, :nested_groups) do |example|
example.run if Group.supports_nested_groups?
end
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index b8ca8f22a3d..c34e76fa72f 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -14,8 +14,10 @@ Capybara.register_driver :poltergeist do |app|
js_errors: true,
timeout: timeout,
window_size: [1366, 768],
+ url_whitelist: %w[localhost 127.0.0.1],
+ url_blacklist: %w[.mp4 .png .gif .avi .bmp .jpg .jpeg],
phantomjs_options: [
- '--load-images=no'
+ '--load-images=yes'
]
)
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 6f31828b825..7f5769209bb 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -19,6 +19,10 @@ RSpec.configure do |config|
DatabaseCleaner.strategy = :truncation
end
+ config.before(:each, :migration) do
+ DatabaseCleaner.strategy = :truncation
+ end
+
config.before(:each) do
DatabaseCleaner.start
end
diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb
new file mode 100644
index 00000000000..0d80c95e826
--- /dev/null
+++ b/spec/support/features/reportable_note_shared_examples.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+
+shared_examples 'reportable note' do
+ include NotesHelper
+
+ let(:comment) { find("##{ActionView::RecordIdentifier.dom_id(note)}") }
+ let(:more_actions_selector) { '.more-actions.dropdown' }
+ let(:abuse_report_path) { new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) }
+
+ it 'has a `More actions` dropdown' do
+ expect(comment).to have_selector(more_actions_selector)
+ end
+
+ it 'dropdown has Edit, Report and Delete links' do
+ dropdown = comment.find(more_actions_selector)
+
+ dropdown.click
+ dropdown.find('.dropdown-menu li', match: :first)
+
+ expect(dropdown).to have_button('Edit comment')
+ expect(dropdown).to have_link('Report as abuse', href: abuse_report_path)
+ expect(dropdown).to have_link('Delete comment', href: note_url(note, project))
+ end
+
+ it 'Report button links to a report page' do
+ dropdown = comment.find(more_actions_selector)
+
+ dropdown.click
+ dropdown.find('.dropdown-menu li', match: :first)
+
+ dropdown.click_link('Report as abuse')
+
+ expect(find('#user_name')['value']).to match(note.author.username)
+ expect(find('#abuse_report_message')['value']).to match(noteable_note_url(note))
+ end
+end
diff --git a/spec/support/helpers/note_interaction_helpers.rb b/spec/support/helpers/note_interaction_helpers.rb
new file mode 100644
index 00000000000..551c759133c
--- /dev/null
+++ b/spec/support/helpers/note_interaction_helpers.rb
@@ -0,0 +1,8 @@
+module NoteInteractionHelpers
+ def open_more_actions_dropdown(note)
+ note_element = find("#note_#{note.id}")
+
+ note_element.find('.more-actions').click
+ note_element.find('.more-actions .dropdown-menu li', match: :first)
+ end
+end
diff --git a/spec/support/javascript_fixtures_helpers.rb b/spec/support/javascript_fixtures_helpers.rb
index a982b159b48..aace4b3adee 100644
--- a/spec/support/javascript_fixtures_helpers.rb
+++ b/spec/support/javascript_fixtures_helpers.rb
@@ -48,7 +48,7 @@ module JavaScriptFixturesHelpers
link_tags = doc.css('link')
link_tags.remove
- scripts = doc.css("script:not([type='text/template'])")
+ scripts = doc.css("script:not([type='text/template']):not([type='text/x-template'])")
scripts.remove
fixture = doc.to_html
diff --git a/spec/support/kubernetes_helpers.rb b/spec/support/kubernetes_helpers.rb
index 9280fad4ace..c92f78b324c 100644
--- a/spec/support/kubernetes_helpers.rb
+++ b/spec/support/kubernetes_helpers.rb
@@ -1,7 +1,26 @@
module KubernetesHelpers
include Gitlab::Kubernetes
- def kube_discovery_body
+ def kube_response(body)
+ { body: body.to_json }
+ end
+
+ def kube_pods_response
+ kube_response(kube_pods_body)
+ end
+
+ def stub_kubeclient_discover
+ WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body))
+ end
+
+ def stub_kubeclient_pods(response = nil)
+ stub_kubeclient_discover
+ pods_url = service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods"
+
+ WebMock.stub_request(:get, pods_url).to_return(response || kube_pods_response)
+ end
+
+ def kube_v1_discovery_body
{
"kind" => "APIResourceList",
"resources" => [
@@ -10,17 +29,19 @@ module KubernetesHelpers
}
end
- def kube_pods_body(*pods)
- { "kind" => "PodList",
- "items" => [kube_pod] }
+ def kube_pods_body
+ {
+ "kind" => "PodList",
+ "items" => [kube_pod]
+ }
end
# This is a partial response, it will have many more elements in reality but
# these are the ones we care about at the moment
- def kube_pod(app: "valid-pod-label")
+ def kube_pod(name: "kube-pod", app: "valid-pod-label")
{
"metadata" => {
- "name" => "kube-pod",
+ "name" => name,
"creationTimestamp" => "2016-11-25T19:55:19Z",
"labels" => { "app" => app }
},
diff --git a/spec/support/matchers/gitaly_matchers.rb b/spec/support/matchers/gitaly_matchers.rb
index ed14bcec9f2..ebfabcd8f24 100644
--- a/spec/support/matchers/gitaly_matchers.rb
+++ b/spec/support/matchers/gitaly_matchers.rb
@@ -1,5 +1,10 @@
-RSpec::Matchers.define :gitaly_request_with_repo_path do |path|
- match { |actual| actual.repository.path == path }
+RSpec::Matchers.define :gitaly_request_with_path do |storage_name, relative_path|
+ match do |actual|
+ repository = actual.repository
+
+ repository.storage_name == storage_name &&
+ repository.relative_path == relative_path
+ end
end
RSpec::Matchers.define :gitaly_request_with_params do |params|
diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb
new file mode 100644
index 00000000000..91fbb4eaf48
--- /dev/null
+++ b/spec/support/migrations_helpers.rb
@@ -0,0 +1,29 @@
+module MigrationsHelpers
+ def table(name)
+ Class.new(ActiveRecord::Base) { self.table_name = name }
+ end
+
+ def migrations_paths
+ ActiveRecord::Migrator.migrations_paths
+ end
+
+ def table_exists?(name)
+ ActiveRecord::Base.connection.table_exists?(name)
+ end
+
+ def migrations
+ ActiveRecord::Migrator.migrations(migrations_paths)
+ end
+
+ def previous_migration
+ migrations.each_cons(2) do |previous, migration|
+ break previous if migration.name == described_class.name
+ end
+ end
+
+ def migrate!
+ ActiveRecord::Migrator.up(migrations_paths) do |migration|
+ migration.name == described_class.name
+ end
+ end
+end
diff --git a/spec/support/milestone_tabs_examples.rb b/spec/support/milestone_tabs_examples.rb
index 4ad8b0a16e1..70b499198bf 100644
--- a/spec/support/milestone_tabs_examples.rb
+++ b/spec/support/milestone_tabs_examples.rb
@@ -1,17 +1,23 @@
shared_examples 'milestone tabs' do
def go(path, extra_params = {})
- params = if milestone.is_a?(GlobalMilestone)
- { group_id: group.to_param, id: milestone.safe_title, title: milestone.title }
- else
- { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
- end
+ params =
+ case milestone
+ when DashboardMilestone
+ { id: milestone.safe_title, title: milestone.title }
+ when GroupMilestone
+ { group_id: group.to_param, id: milestone.safe_title, title: milestone.title }
+ else
+ { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
+ end
get path, params.merge(extra_params)
end
describe '#merge_requests' do
context 'as html' do
- before { go(:merge_requests, format: 'html') }
+ before do
+ go(:merge_requests, format: 'html')
+ end
it 'redirects to milestone#show' do
expect(response).to redirect_to(milestone_path)
@@ -19,7 +25,9 @@ shared_examples 'milestone tabs' do
end
context 'as json' do
- before { go(:merge_requests, format: 'json') }
+ before do
+ go(:merge_requests, format: 'json')
+ end
it 'renders the merge requests tab template to a string' do
expect(response).to render_template('shared/milestones/_merge_requests_tab')
@@ -30,7 +38,9 @@ shared_examples 'milestone tabs' do
describe '#participants' do
context 'as html' do
- before { go(:participants, format: 'html') }
+ before do
+ go(:participants, format: 'html')
+ end
it 'redirects to milestone#show' do
expect(response).to redirect_to(milestone_path)
@@ -38,7 +48,9 @@ shared_examples 'milestone tabs' do
end
context 'as json' do
- before { go(:participants, format: 'json') }
+ before do
+ go(:participants, format: 'json')
+ end
it 'renders the participants tab template to a string' do
expect(response).to render_template('shared/milestones/_participants_tab')
@@ -49,7 +61,9 @@ shared_examples 'milestone tabs' do
describe '#labels' do
context 'as html' do
- before { go(:labels, format: 'html') }
+ before do
+ go(:labels, format: 'html')
+ end
it 'redirects to milestone#show' do
expect(response).to redirect_to(milestone_path)
@@ -57,7 +71,9 @@ shared_examples 'milestone tabs' do
end
context 'as json' do
- before { go(:labels, format: 'json') }
+ before do
+ go(:labels, format: 'json')
+ end
it 'renders the labels tab template to a string' do
expect(response).to render_template('shared/milestones/_labels_tab')
diff --git a/spec/support/reference_parser_shared_examples.rb b/spec/support/reference_parser_shared_examples.rb
index 8eb74635a60..bd83cb88058 100644
--- a/spec/support/reference_parser_shared_examples.rb
+++ b/spec/support/reference_parser_shared_examples.rb
@@ -3,7 +3,9 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features|
related_features.map { |feature| (feature + "_access_level").to_sym }
end
- before { link['data-project'] = project.id.to_s }
+ before do
+ link['data-project'] = project.id.to_s
+ end
context "when feature is disabled" do
it "does not create reference" do
@@ -13,7 +15,9 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features|
end
context "when feature is enabled only for team members" do
- before { set_features_fields_to(ProjectFeature::PRIVATE) }
+ before do
+ set_features_fields_to(ProjectFeature::PRIVATE)
+ end
it "does not create reference for non member" do
non_member = create(:user)
diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
index 1dd3663b944..5e6f9f323a1 100644
--- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
+++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
@@ -11,7 +11,9 @@ shared_examples 'new issuable record that supports slash commands' do
let(:params) { base_params.merge(defined?(default_params) ? default_params : {}).merge(example_params) }
let(:issuable) { described_class.new(project, user, params).execute }
- before { project.team << [assignee, :master] }
+ before do
+ project.team << [assignee, :master]
+ end
context 'with labels in command only' do
let(:example_params) do
diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb
index 8947f20562f..ffbce6c42bf 100644
--- a/spec/support/services/issuable_update_service_shared_examples.rb
+++ b/spec/support/services/issuable_update_service_shared_examples.rb
@@ -4,7 +4,9 @@ shared_examples 'issuable update service' do
end
context 'changing state' do
- before { expect(project).to receive(:execute_hooks).once }
+ before do
+ expect(project).to receive(:execute_hooks).once
+ end
context 'to reopened' do
it 'executes hooks only once' do
diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb
index 7e35ebb6c97..a7deb038703 100644
--- a/spec/support/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/slack_mattermost_notifications_shared_examples.rb
@@ -11,14 +11,18 @@ RSpec.shared_examples 'slack or mattermost notifications' do
describe 'Validations' do
context 'when service is active' do
- before { subject.active = true }
+ before do
+ subject.active = true
+ end
it { is_expected.to validate_presence_of(:webhook) }
it_behaves_like 'issue tracker service URL attribute', :webhook
end
context 'when service is inactive' do
- before { subject.active = false }
+ before do
+ subject.active = false
+ end
it { is_expected.not_to validate_presence_of(:webhook) }
end
diff --git a/spec/support/target_branch_helpers.rb b/spec/support/target_branch_helpers.rb
deleted file mode 100644
index 01d1c53fe6c..00000000000
--- a/spec/support/target_branch_helpers.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module TargetBranchHelpers
- def select_branch(name)
- first('button.js-target-branch').click
- wait_for_requests
- all('a[data-group="Branches"]').find do |el|
- el.text == name
- end.click
- end
-
- def create_new_branch(name)
- first('button.js-target-branch').click
- click_link 'Create new branch'
- fill_in 'new_branch_name', with: name
- click_button 'Create'
- end
-end
diff --git a/spec/support/unique_ip_check_shared_examples.rb b/spec/support/unique_ip_check_shared_examples.rb
index 7cf5a65eeed..1986d202c4a 100644
--- a/spec/support/unique_ip_check_shared_examples.rb
+++ b/spec/support/unique_ip_check_shared_examples.rb
@@ -31,7 +31,9 @@ end
shared_examples 'user login operation with unique ip limit' do
include_context 'unique ips sign in limit' do
- before { current_application_settings.update!(unique_ips_limit_per_user: 1) }
+ before do
+ current_application_settings.update!(unique_ips_limit_per_user: 1)
+ end
it 'allows user authenticating from the same ip' do
expect { operation_from_ip('ip') }.not_to raise_error
@@ -47,7 +49,9 @@ end
shared_examples 'user login request with unique ip limit' do |success_status = 200|
include_context 'unique ips sign in limit' do
- before { current_application_settings.update!(unique_ips_limit_per_user: 1) }
+ before do
+ current_application_settings.update!(unique_ips_limit_per_user: 1)
+ end
it 'allows user authenticating from the same ip' do
expect(request_from_ip('ip')).to have_http_status(success_status)
diff --git a/spec/support/updating_mentions_shared_examples.rb b/spec/support/updating_mentions_shared_examples.rb
index e0c59a5c280..eeec3e1d79b 100644
--- a/spec/support/updating_mentions_shared_examples.rb
+++ b/spec/support/updating_mentions_shared_examples.rb
@@ -2,7 +2,9 @@ RSpec.shared_examples 'updating mentions' do |service_class|
let(:mentioned_user) { create(:user) }
let(:service_class) { service_class }
- before { project.team << [mentioned_user, :developer] }
+ before do
+ project.team << [mentioned_user, :developer]
+ end
def update_mentionable(opts)
reset_delivered_emails!
@@ -15,7 +17,9 @@ RSpec.shared_examples 'updating mentions' do |service_class|
end
context 'in title' do
- before { update_mentionable(title: mentioned_user.to_reference) }
+ before do
+ update_mentionable(title: mentioned_user.to_reference)
+ end
it 'emails only the newly-mentioned user' do
should_only_email(mentioned_user)
@@ -23,7 +27,9 @@ RSpec.shared_examples 'updating mentions' do |service_class|
end
context 'in description' do
- before { update_mentionable(description: mentioned_user.to_reference) }
+ before do
+ update_mentionable(description: mentioned_user.to_reference)
+ end
it 'emails only the newly-mentioned user' do
should_only_email(mentioned_user)
diff --git a/spec/support/wait_for_requests.rb b/spec/support/wait_for_requests.rb
index 05ec9026141..1cbe609c0e0 100644
--- a/spec/support/wait_for_requests.rb
+++ b/spec/support/wait_for_requests.rb
@@ -7,7 +7,7 @@ module WaitForRequests
def block_and_wait_for_requests_complete
Gitlab::Testing::RequestBlockerMiddleware.block_requests!
wait_for('pending requests complete') do
- Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero?
+ Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero? && finished_all_requests?
end
ensure
Gitlab::Testing::RequestBlockerMiddleware.allow_requests!
@@ -40,13 +40,13 @@ module WaitForRequests
end
def finished_all_vue_resource_requests?
- page.evaluate_script('window.activeVueResources || 0').zero?
+ Capybara.page.evaluate_script('window.activeVueResources || 0').zero?
end
def finished_all_ajax_requests?
- return true if page.evaluate_script('typeof jQuery === "undefined"')
+ return true if Capybara.page.evaluate_script('typeof jQuery === "undefined"')
- page.evaluate_script('jQuery.active').zero?
+ Capybara.page.evaluate_script('jQuery.active').zero?
end
def javascript_test?
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 0ff1a988a9e..1e5f55a738a 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -241,6 +241,10 @@ describe 'gitlab:app namespace rake task' do
project_a
project_b
+ # Avoid asking gitaly about the root ref (which will fail beacuse of the
+ # mocked storages)
+ allow_any_instance_of(Repository).to receive(:empty_repo?).and_return(false)
+
# We only need a backup of the repositories for this test
ENV["SKIP"] = "db,uploads,builds,artifacts,lfs,registry"
create_backup
diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb
index 4a636decafd..cfa6c9ca8ce 100644
--- a/spec/tasks/gitlab/gitaly_rake_spec.rb
+++ b/spec/tasks/gitlab/gitaly_rake_spec.rb
@@ -79,8 +79,14 @@ describe 'gitlab:gitaly namespace rake task' do
describe 'storage_config' do
it 'prints storage configuration in a TOML format' do
config = {
- 'default' => { 'path' => '/path/to/default' },
- 'nfs_01' => { 'path' => '/path/to/nfs_01' }
+ 'default' => {
+ 'path' => '/path/to/default',
+ 'gitaly_address' => 'unix:/path/to/my.socket'
+ },
+ 'nfs_01' => {
+ 'path' => '/path/to/nfs_01',
+ 'gitaly_address' => 'unix:/path/to/my.socket'
+ }
}
allow(Gitlab.config.repositories).to receive(:storages).and_return(config)
@@ -89,6 +95,7 @@ describe 'gitlab:gitaly namespace rake task' do
expected_output = <<~TOML
# Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)}
# This is in TOML format suitable for use in Gitaly's config.toml file.
+ socket_path = "/path/to/my.socket"
[[storage]]
name = "default"
path = "/path/to/default"
diff --git a/spec/unicorn/unicorn_spec.rb b/spec/unicorn/unicorn_spec.rb
index 8518c047a47..41de94d35c2 100644
--- a/spec/unicorn/unicorn_spec.rb
+++ b/spec/unicorn/unicorn_spec.rb
@@ -67,8 +67,8 @@ describe 'Unicorn' do
end
def wait_unicorn_boot!(master_pid, ready_file)
- # Unicorn should boot in under 60 seconds so 120 seconds seems like a good timeout.
- timeout = 120
+ # We have seen the boot timeout after 2 minutes in CI so let's set it to 5 minutes.
+ timeout = 5 * 60
timeout.times do
return if File.exist?(ready_file)
pid = Process.waitpid(master_pid, Process::WNOHANG)
diff --git a/spec/uploaders/artifact_uploader_spec.rb b/spec/uploaders/artifact_uploader_spec.rb
index 24e2e3a9f0e..2a3bd0e3bb2 100644
--- a/spec/uploaders/artifact_uploader_spec.rb
+++ b/spec/uploaders/artifact_uploader_spec.rb
@@ -17,22 +17,45 @@ describe ArtifactUploader do
describe '.artifacts_upload_path' do
subject { described_class.artifacts_upload_path }
-
+
it { is_expected.to start_with(path) }
it { is_expected.to end_with('tmp/uploads/') }
end
describe '#store_dir' do
subject { uploader.store_dir }
-
+
it { is_expected.to start_with(path) }
it { is_expected.to end_with("#{job.project_id}/#{job.id}") }
end
describe '#cache_dir' do
subject { uploader.cache_dir }
-
+
+ it { is_expected.to start_with(path) }
+ it { is_expected.to end_with('/tmp/cache') }
+ end
+
+ describe '#work_dir' do
+ subject { uploader.work_dir }
+
it { is_expected.to start_with(path) }
- it { is_expected.to end_with('tmp/cache') }
+ it { is_expected.to end_with('/tmp/work') }
+ end
+
+ describe '#filename' do
+ # we need to use uploader, as this makes to use mounter
+ # which initialises uploader.file object
+ let(:uploader) { job.artifacts_file }
+
+ subject { uploader.filename }
+
+ it { is_expected.to be_nil }
+
+ context 'with artifacts' do
+ let(:job) { create(:ci_build, :artifacts) }
+
+ it { is_expected.not_to be_nil }
+ end
end
end
diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb
index ea714fb08f0..d82dbe871d5 100644
--- a/spec/uploaders/attachment_uploader_spec.rb
+++ b/spec/uploaders/attachment_uploader_spec.rb
@@ -3,6 +3,17 @@ require 'spec_helper'
describe AttachmentUploader do
let(:uploader) { described_class.new(build_stubbed(:user)) }
+ describe "#store_dir" do
+ it "stores in the system dir" do
+ expect(uploader.store_dir).to start_with("uploads/system/user")
+ end
+
+ it "uses the old path when using object storage" do
+ expect(described_class).to receive(:file_storage?).and_return(false)
+ expect(uploader.store_dir).to start_with("uploads/user")
+ end
+ end
+
describe '#move_to_cache' do
it 'is true' do
expect(uploader.move_to_cache).to eq(true)
diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb
index c4d558805ab..201fe6949aa 100644
--- a/spec/uploaders/avatar_uploader_spec.rb
+++ b/spec/uploaders/avatar_uploader_spec.rb
@@ -3,6 +3,17 @@ require 'spec_helper'
describe AvatarUploader do
let(:uploader) { described_class.new(build_stubbed(:user)) }
+ describe "#store_dir" do
+ it "stores in the system dir" do
+ expect(uploader.store_dir).to start_with("uploads/system/user")
+ end
+
+ it "uses the old path when using object storage" do
+ expect(described_class).to receive(:file_storage?).and_return(false)
+ expect(uploader.store_dir).to start_with("uploads/user")
+ end
+ end
+
describe '#move_to_cache' do
it 'is false' do
expect(uploader.move_to_cache).to eq(false)
diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb
new file mode 100644
index 00000000000..896cb410ed5
--- /dev/null
+++ b/spec/uploaders/file_mover_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+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)'
+ 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(:snippet) { create(:personal_snippet, description: temp_description) }
+
+ subject { described_class.new(file_path, snippet).execute }
+
+ describe '#execute' do
+ before do
+ expect(FileUtils).to receive(:mkdir_p).with(a_string_including(File.dirname(file_path)))
+ expect(FileUtils).to receive(:move).with(a_string_including(temp_file_path), a_string_including(file_path))
+ allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:exists?).and_return(true)
+ allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:size).and_return(10)
+ end
+
+ context 'when move and field update successful' do
+ it 'updates the description correctly' do
+ subject
+
+ 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)"
+ )
+ end
+
+ it 'creates a new update record' do
+ expect { subject }.to change { Upload.count }.by(1)
+ end
+ end
+
+ context 'when update_markdown fails' do
+ before do
+ expect(FileUtils).to receive(:move).with(a_string_including(file_path), a_string_including(temp_file_path))
+ end
+
+ subject { described_class.new(file_path, snippet, :non_existing_field).execute }
+
+ it 'does not update the description' do
+ subject
+
+ expect(snippet.reload.description)
+ .to eq(
+ "test ![banana_sample](/uploads/temp/secret55/banana_sample.gif)"\
+ " same ![banana_sample](/uploads/temp/secret55/banana_sample.gif)"
+ )
+ end
+
+ it 'does not create a new update record' do
+ expect { subject }.not_to change { Upload.count }
+ end
+ end
+ end
+end
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index d9113ef4095..47e9365e13d 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -15,6 +15,16 @@ describe FileUploader do
end
end
+ describe "#store_dir" do
+ it "stores in the namespace path" do
+ project = build_stubbed(:empty_project)
+ uploader = described_class.new(project)
+
+ expect(uploader.store_dir).to include(project.path_with_namespace)
+ expect(uploader.store_dir).not_to include("system")
+ end
+ end
+
describe 'initialize' do
it 'generates a secret if none is provided' do
expect(SecureRandom).to receive(:hex).and_return('secret')
diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb
index 78e9d9cf46c..a144b39f74f 100644
--- a/spec/uploaders/gitlab_uploader_spec.rb
+++ b/spec/uploaders/gitlab_uploader_spec.rb
@@ -53,4 +53,19 @@ describe GitlabUploader do
expect(subject.move_to_store).to eq(true)
end
end
+
+ describe '#cache!' do
+ it 'moves the file from the working directory to the cache directory' do
+ # One to get the work dir, the other to remove it
+ expect(subject).to receive(:workfile_path).exactly(2).times.and_call_original
+ # Test https://github.com/carrierwavesubject/carrierwave/blob/v1.0.0/lib/carrierwave/sanitized_file.rb#L200
+ expect(FileUtils).to receive(:mv).with(anything, /^#{subject.work_dir}/).and_call_original
+ expect(FileUtils).to receive(:mv).with(/^#{subject.work_dir}/, /#{subject.cache_dir}/).and_call_original
+
+ fixture = Rails.root.join('spec', 'fixtures', 'rails_sample.jpg')
+ subject.cache!(fixture_file_upload(fixture))
+
+ expect(subject.file.path).to match(/#{subject.cache_dir}/)
+ end
+ end
end
diff --git a/spec/uploaders/lfs_object_uploader_spec.rb b/spec/uploaders/lfs_object_uploader_spec.rb
index c3b72e7d677..7088bc23334 100644
--- a/spec/uploaders/lfs_object_uploader_spec.rb
+++ b/spec/uploaders/lfs_object_uploader_spec.rb
@@ -1,21 +1,9 @@
require 'spec_helper'
describe LfsObjectUploader do
- let(:uploader) { described_class.new(build_stubbed(:empty_project)) }
-
- describe '#cache!' do
- it 'caches the file in the cache directory' do
- # One to get the work dir, the other to remove it
- expect(uploader).to receive(:workfile_path).exactly(2).times.and_call_original
- expect(FileUtils).to receive(:mv).with(anything, /^#{uploader.work_dir}/).and_call_original
- expect(FileUtils).to receive(:mv).with(/^#{uploader.work_dir}/, /^#{uploader.cache_dir}/).and_call_original
-
- fixture = Rails.root.join('spec', 'fixtures', 'rails_sample.jpg')
- uploader.cache!(fixture_file_upload(fixture))
-
- expect(uploader.file.path).to start_with(uploader.cache_dir)
- end
- end
+ let(:lfs_object) { create(:lfs_object, :with_file) }
+ let(:uploader) { described_class.new(lfs_object) }
+ let(:path) { Gitlab.config.lfs.storage_path }
describe '#move_to_cache' do
it 'is true' do
@@ -28,4 +16,25 @@ describe LfsObjectUploader do
expect(uploader.move_to_store).to eq(true)
end
end
+
+ describe '#store_dir' do
+ subject { uploader.store_dir }
+
+ it { is_expected.to start_with(path) }
+ it { is_expected.to end_with("#{lfs_object.oid[0, 2]}/#{lfs_object.oid[2, 2]}") }
+ end
+
+ describe '#cache_dir' do
+ subject { uploader.cache_dir }
+
+ it { is_expected.to start_with(path) }
+ it { is_expected.to end_with('/tmp/cache') }
+ end
+
+ describe '#work_dir' do
+ subject { uploader.work_dir }
+
+ it { is_expected.to start_with(path) }
+ it { is_expected.to end_with('/tmp/work') }
+ end
end
diff --git a/spec/uploaders/records_uploads_spec.rb b/spec/uploaders/records_uploads_spec.rb
index 5c26e334a6e..bb32ee62ccb 100644
--- a/spec/uploaders/records_uploads_spec.rb
+++ b/spec/uploaders/records_uploads_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
describe RecordsUploads do
- let(:uploader) do
+ let!(:uploader) do
class RecordsUploadsExampleUploader < GitlabUploader
include RecordsUploads
@@ -57,6 +57,13 @@ describe RecordsUploads do
uploader.store!(upload_fixture('rails_sample.jpg'))
end
+ it 'does not create an Upload record if model is missing' do
+ expect_any_instance_of(RecordsUploadsExampleUploader).to receive(:model).and_return(nil)
+ expect(Upload).not_to receive(:record).with(uploader)
+
+ uploader.store!(upload_fixture('rails_sample.jpg'))
+ end
+
it 'it destroys Upload records at the same path before recording' do
existing = Upload.create!(
path: File.join('uploads', 'rails_sample.jpg'),
diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb
index 6b07fcfc987..1f8261cc46b 100644
--- a/spec/views/help/index.html.haml_spec.rb
+++ b/spec/views/help/index.html.haml_spec.rb
@@ -21,7 +21,7 @@ describe 'help/index' do
render
expect(rendered).to match '8.0.2'
- expect(rendered).to match 'abcdefg'
+ expect(rendered).to have_link('abcdefg', 'https://gitlab.com/gitlab-org/gitlab-ce/commits/abcdefg')
end
end
diff --git a/spec/views/projects/diffs/_viewer.html.haml_spec.rb b/spec/views/projects/diffs/_viewer.html.haml_spec.rb
new file mode 100644
index 00000000000..32469202508
--- /dev/null
+++ b/spec/views/projects/diffs/_viewer.html.haml_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+
+describe 'projects/diffs/_viewer.html.haml', :view do
+ include FakeBlobHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
+ let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
+
+ let(:viewer_class) do
+ Class.new(DiffViewer::Base) do
+ include DiffViewer::Rich
+
+ self.partial_name = 'text'
+ end
+ end
+
+ let(:viewer) { viewer_class.new(diff_file) }
+
+ before do
+ assign(:project, project)
+
+ controller.params[:controller] = 'projects/commit'
+ controller.params[:action] = 'show'
+ controller.params[:namespace_id] = project.namespace.to_param
+ controller.params[:project_id] = project.to_param
+ controller.params[:id] = commit.id
+ end
+
+ def render_view
+ render partial: 'projects/diffs/viewer', locals: { viewer: viewer }
+ end
+
+ context 'when there is a render error' do
+ before do
+ allow(viewer).to receive(:render_error).and_return(:too_large)
+ end
+
+ it 'renders the error' do
+ render_view
+
+ expect(view).to render_template('projects/diffs/_render_error')
+ end
+ end
+
+ context 'when the viewer is collapsed' do
+ before do
+ allow(diff_file).to receive(:collapsed?).and_return(true)
+ end
+
+ it 'renders the collapsed view' do
+ render_view
+
+ expect(view).to render_template('projects/diffs/_collapsed')
+ end
+ end
+
+ context 'when there is no render error' do
+ it 'prepares the viewer' do
+ expect(viewer).to receive(:prepare!)
+
+ render_view
+ end
+
+ it 'renders the viewer' do
+ render_view
+
+ expect(view).to render_template('projects/diffs/viewers/_text')
+ end
+ end
+end
diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb
index 8f2822f5dc5..d9a7ba265f8 100644
--- a/spec/views/projects/jobs/show.html.haml_spec.rb
+++ b/spec/views/projects/jobs/show.html.haml_spec.rb
@@ -15,36 +15,6 @@ describe 'projects/jobs/show', :view do
allow(view).to receive(:can?).and_return(true)
end
- describe 'job information in header' do
- let(:build) do
- create(:ci_build, :success, environment: 'staging')
- end
-
- before do
- render
- end
-
- it 'shows status name' do
- expect(rendered).to have_css('.ci-status.ci-success', text: 'passed')
- end
-
- it 'does not render a link to the job' do
- expect(rendered).not_to have_link('passed')
- end
-
- it 'shows job id' do
- expect(rendered).to have_css('.js-build-id', text: build.id)
- end
-
- it 'shows a link to the pipeline' do
- expect(rendered).to have_link(build.pipeline.id)
- end
-
- it 'shows a link to the commit' do
- expect(rendered).to have_link(build.pipeline.short_sha)
- end
- end
-
describe 'environment info in job view' do
context 'job with latest deployment' do
let(:build) do
@@ -215,34 +185,6 @@ describe 'projects/jobs/show', :view do
end
end
- context 'when job is not running' do
- before do
- build.success!
- render
- end
-
- it 'shows retry button' do
- expect(rendered).to have_link('Retry')
- end
-
- context 'if build passed' do
- it 'does not show New issue button' do
- expect(rendered).not_to have_link('New issue')
- end
- end
-
- context 'if build failed' do
- before do
- build.status = 'failed'
- render
- end
-
- it 'shows New issue button' do
- expect(rendered).to have_link('New issue')
- end
- end
- end
-
describe 'commit title in sidebar' do
let(:commit_title) { project.commit.title }
@@ -269,25 +211,4 @@ describe 'projects/jobs/show', :view do
expect(rendered).to have_css('.js-build-value', visible: false, text: 'TRIGGER_VALUE_2')
end
end
-
- describe 'New issue button' do
- before do
- build.status = 'failed'
- render
- end
-
- it 'links to issues/new with the title and description filled in' do
- title = "Build Failed ##{build.id}"
- build_url = namespace_project_job_url(project.namespace, project, build)
- href = new_namespace_project_issue_path(
- project.namespace,
- project,
- issue: {
- title: title,
- description: build_url
- }
- )
- expect(rendered).to have_link('New issue', href: href)
- end
- end
end
diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb
new file mode 100644
index 00000000000..0d742ae9dc7
--- /dev/null
+++ b/spec/workers/background_migration_worker_spec.rb
@@ -0,0 +1,13 @@
+require 'spec_helper'
+
+describe BackgroundMigrationWorker do
+ describe '.perform' do
+ it 'performs a background migration' do
+ expect(Gitlab::BackgroundMigration).
+ to receive(:perform).
+ with('Foo', [10, 20])
+
+ described_class.new.perform('Foo', [10, 20])
+ end
+ end
+end
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
index a0ed85cc0b3..5b6b38e0f76 100644
--- a/spec/workers/emails_on_push_worker_spec.rb
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -71,7 +71,9 @@ describe EmailsOnPushWorker do
end
context "when there are no errors in sending" do
- before { perform }
+ before do
+ perform
+ end
it "sends a mail with the correct subject" do
expect(email.subject).to include('adds bar folder and branch-test text file')
diff --git a/spec/workers/expire_build_artifacts_worker_spec.rb b/spec/workers/expire_build_artifacts_worker_spec.rb
index 73cbadc13d9..b47b4a02a68 100644
--- a/spec/workers/expire_build_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_artifacts_worker_spec.rb
@@ -5,10 +5,14 @@ describe ExpireBuildArtifactsWorker do
let(:worker) { described_class.new }
- before { Sidekiq::Worker.clear_all }
+ before do
+ Sidekiq::Worker.clear_all
+ end
describe '#perform' do
- before { build }
+ before do
+ build
+ end
subject! do
Sidekiq::Testing.fake! { worker.perform }
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 8c5303b61cc..f443bb2c9b4 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -23,7 +23,9 @@ describe GitGarbageCollectWorker do
end
shared_examples 'gc tasks' do
- before { allow(subject).to receive(:bitmaps_enabled?).and_return(bitmaps_enabled) }
+ before do
+ allow(subject).to receive(:bitmaps_enabled?).and_return(bitmaps_enabled)
+ end
it 'incremental repack adds a new packfile' do
create_objects(project)
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index f4bc63bcc6a..3c93da63f2e 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -89,31 +89,30 @@ describe PostReceive do
end
context "does not create a Ci::Pipeline" do
- before { stub_ci_pipeline_yaml_file(nil) }
+ before do
+ stub_ci_pipeline_yaml_file(nil)
+ end
it { expect{ subject }.not_to change{ Ci::Pipeline.count } }
end
end
- end
- describe '#process_repository_update' do
- let(:changes) {'123456 789012 refs/heads/tést'}
- let(:fake_hook_data) do
- { event_name: 'repository_update' }
- end
+ context 'after project changes hooks' do
+ let(:changes) { '123456 789012 refs/heads/tést' }
+ let(:fake_hook_data) { Hash.new(event_name: 'repository_update') }
- before do
- allow_any_instance_of(Gitlab::GitPostReceive).to receive(:identify).and_return(project.owner)
- allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data)
- # silence hooks so we can isolate
- allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true)
- allow(subject).to receive(:process_project_changes).and_return(true)
- end
+ before do
+ allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data)
+ # silence hooks so we can isolate
+ allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true)
+ allow_any_instance_of(GitPushService).to receive(:execute).and_return(true)
+ end
- it 'calls SystemHooksService' do
- expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true)
+ it 'calls SystemHooksService' do
+ expect_any_instance_of(SystemHooksService).to receive(:execute_hooks).with(fake_hook_data, :repository_update_hooks).and_return(true)
- subject.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(project_identifier, key_id, base64_changes)
+ end
end
end
diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb
index 8434b0c8e5b..549635f7f33 100644
--- a/spec/workers/stuck_ci_jobs_worker_spec.rb
+++ b/spec/workers/stuck_ci_jobs_worker_spec.rb
@@ -34,7 +34,9 @@ describe StuckCiJobsWorker do
let(:status) { 'pending' }
context 'when job is not stuck' do
- before { allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(false) }
+ before do
+ allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(false)
+ end
context 'when job was not updated for more than 1 day ago' do
let(:updated_at) { 2.days.ago }
@@ -53,7 +55,9 @@ describe StuckCiJobsWorker do
end
context 'when job is stuck' do
- before { allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(true) }
+ before do
+ allow_any_instance_of(Ci::Build).to receive(:stuck?).and_return(true)
+ end
context 'when job was not updated for more than 1 hour ago' do
let(:updated_at) { 2.hours.ago }
@@ -93,7 +97,9 @@ describe StuckCiJobsWorker do
let(:status) { 'running' }
let(:updated_at) { 2.days.ago }
- before { job.project.update(pending_delete: true) }
+ before do
+ job.project.update(pending_delete: true)
+ end
it 'does not drop job' do
expect_any_instance_of(Ci::Build).not_to receive(:drop)