summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb2
-rw-r--r--spec/controllers/abuse_reports_controller_spec.rb36
-rw-r--r--spec/controllers/admin/impersonation_controller_spec.rb19
-rw-r--r--spec/controllers/autocomplete_controller_spec.rb9
-rw-r--r--spec/controllers/commit_controller_spec.rb35
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb27
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb24
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb5
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb34
-rw-r--r--spec/controllers/projects_controller_spec.rb16
-rw-r--r--spec/controllers/snippets_controller_spec.rb115
-rw-r--r--spec/factories.rb3
-rw-r--r--spec/factories/ci/builds.rb4
-rw-r--r--spec/factories/ci/commits.rb25
-rw-r--r--spec/factories/ci/events.rb24
-rw-r--r--spec/factories/ci/projects.rb50
-rw-r--r--spec/factories/ci/runner_projects.rb2
-rw-r--r--spec/factories/ci/web_hook.rb6
-rw-r--r--spec/factories/commit_statuses.rb2
-rw-r--r--spec/factories/lfs_objects.rb12
-rw-r--r--spec/factories/lfs_objects_projects.rb11
-rw-r--r--spec/factories/merge_requests.rb5
-rw-r--r--spec/factories/notes.rb1
-rw-r--r--spec/factories/projects.rb1
-rw-r--r--spec/features/admin/admin_builds_spec.rb (renamed from spec/features/ci/admin/builds_spec.rb)35
-rw-r--r--spec/features/admin/admin_runners_spec.rb (renamed from spec/features/ci/admin/runners_spec.rb)32
-rw-r--r--spec/features/admin/admin_users_spec.rb17
-rw-r--r--spec/features/builds_spec.rb34
-rw-r--r--spec/features/ci/admin/events_spec.rb20
-rw-r--r--spec/features/ci/admin/projects_spec.rb19
-rw-r--r--spec/features/ci_settings_spec.rb22
-rw-r--r--spec/features/ci_web_hooks_spec.rb27
-rw-r--r--spec/features/commits_spec.rb95
-rw-r--r--spec/features/issues/filter_by_milestone_spec.rb4
-rw-r--r--spec/features/issues/note_polling_spec.rb16
-rw-r--r--spec/features/issues_spec.rb35
-rw-r--r--spec/features/lint_spec.rb (renamed from spec/features/ci/lint_spec.rb)0
-rw-r--r--spec/features/merge_requests/merge_when_build_succeeds_spec.rb85
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb5
-rw-r--r--spec/features/password_reset_spec.rb26
-rw-r--r--spec/features/runners_spec.rb28
-rw-r--r--spec/features/security/group_access_spec.rb4
-rw-r--r--spec/features/task_lists_spec.rb4
-rw-r--r--spec/features/triggers_spec.rb7
-rw-r--r--spec/features/variables_spec.rb7
-rw-r--r--spec/finders/projects_finder_spec.rb17
-rw-r--r--spec/fixtures/markdown.md.erb17
-rw-r--r--spec/helpers/application_helper_spec.rb25
-rw-r--r--spec/helpers/ci_status_helper_spec.rb11
-rw-r--r--spec/helpers/groups_helper.rb2
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb85
-rw-r--r--spec/javascripts/fixtures/issues_show.html.haml2
-rw-r--r--spec/javascripts/fixtures/merge_request_tabs.html.haml6
-rw-r--r--spec/javascripts/fixtures/merge_requests_show.html.haml2
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb34
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb112
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb182
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb163
-rw-r--r--spec/lib/banzai/filter/emoji_filter_spec.rb98
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb77
-rw-r--r--spec/lib/banzai/filter/external_link_filter_spec.rb29
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb209
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb179
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb142
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb89
-rw-r--r--spec/lib/banzai/filter/reference_gatherer_filter_spec.rb87
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb147
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb197
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb146
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb17
-rw-r--r--spec/lib/banzai/filter/table_of_contents_filter_spec.rb97
-rw-r--r--spec/lib/banzai/filter/task_list_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb73
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb147
-rw-r--r--spec/lib/ci/ansi2html_spec.rb2
-rw-r--r--spec/lib/ci/charts_spec.rb2
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb8
-rw-r--r--spec/lib/disable_email_interceptor_spec.rb2
-rw-r--r--spec/lib/extracts_path_spec.rb2
-rw-r--r--spec/lib/file_size_validator_spec.rb2
-rw-r--r--spec/lib/git_ref_validator_spec.rb2
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb8
-rw-r--r--spec/lib/gitlab/auth_spec.rb2
-rw-r--r--spec/lib/gitlab/backend/grack_auth_spec.rb11
-rw-r--r--spec/lib/gitlab/backend/shell_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/build_data_builder_spec.rb20
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb55
-rw-r--r--spec/lib/gitlab/color_schemes_spec.rb2
-rw-r--r--spec/lib/gitlab/database_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/parser_spec.rb2
-rw-r--r--spec/lib/gitlab/email/attachment_uploader_spec.rb2
-rw-r--r--spec/lib/gitlab/email/message/repository_push_spec.rb122
-rw-r--r--spec/lib/gitlab/email/receiver_spec.rb2
-rw-r--r--spec/lib/gitlab/email/reply_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/gitlab_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/gitlab_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/gitorious_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/incoming_email_spec.rb2
-rw-r--r--spec/lib/gitlab/inline_diff_spec.rb2
-rw-r--r--spec/lib/gitlab/key_fingerprint_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/access_spec.rb7
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/authentication_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/config_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb2
-rw-r--r--spec/lib/gitlab/lfs/lfs_router_spec.rb547
-rw-r--r--spec/lib/gitlab/markdown/autolink_filter_spec.rb114
-rw-r--r--spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb145
-rw-r--r--spec/lib/gitlab/markdown/commit_reference_filter_spec.rb135
-rw-r--r--spec/lib/gitlab/markdown/cross_project_reference_spec.rb36
-rw-r--r--spec/lib/gitlab/markdown/emoji_filter_spec.rb95
-rw-r--r--spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb79
-rw-r--r--spec/lib/gitlab/markdown/external_link_filter_spec.rb31
-rw-r--r--spec/lib/gitlab/markdown/issue_reference_filter_spec.rb139
-rw-r--r--spec/lib/gitlab/markdown/label_reference_filter_spec.rb144
-rw-r--r--spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb120
-rw-r--r--spec/lib/gitlab/markdown/redactor_filter_spec.rb91
-rw-r--r--spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb89
-rw-r--r--spec/lib/gitlab/markdown/relative_link_filter_spec.rb149
-rw-r--r--spec/lib/gitlab/markdown/sanitization_filter_spec.rb199
-rw-r--r--spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb118
-rw-r--r--spec/lib/gitlab/markdown/syntax_highlight_filter_spec.rb19
-rw-r--r--spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb99
-rw-r--r--spec/lib/gitlab/markdown/task_list_filter_spec.rb12
-rw-r--r--spec/lib/gitlab/markdown/upload_link_filter_spec.rb75
-rw-r--r--spec/lib/gitlab/markdown/user_reference_filter_spec.rb122
-rw-r--r--spec/lib/gitlab/markup_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/note_data_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/o_auth/auth_hash_spec.rb6
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb2
-rw-r--r--spec/lib/gitlab/popen_spec.rb2
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb2
-rw-r--r--spec/lib/gitlab/push_data_builder_spec.rb11
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb2
-rw-r--r--spec/lib/gitlab/regex_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/collection_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/file_sample_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/line_profiler_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/line_sample_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/location_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/middleware_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/query_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/transaction_spec.rb15
-rw-r--r--spec/lib/gitlab/sql/union_spec.rb2
-rw-r--r--spec/lib/gitlab/themes_spec.rb2
-rw-r--r--spec/lib/gitlab/upgrader_spec.rb2
-rw-r--r--spec/lib/gitlab/uploads_transfer_spec.rb2
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/version_info_spec.rb2
-rw-r--r--spec/lib/repository_cache_spec.rb2
-rw-r--r--spec/mailers/ci/notify_spec.rb35
-rw-r--r--spec/mailers/notify_spec.rb106
-rw-r--r--spec/models/application_setting_spec.rb38
-rw-r--r--spec/models/broadcast_message_spec.rb17
-rw-r--r--spec/models/build_spec.rb85
-rw-r--r--spec/models/ci/commit_spec.rb30
-rw-r--r--spec/models/ci/project_services/hip_chat_message_spec.rb39
-rw-r--r--spec/models/ci/project_services/hip_chat_service_spec.rb73
-rw-r--r--spec/models/ci/project_services/mail_service_spec.rb191
-rw-r--r--spec/models/ci/project_services/slack_message_spec.rb43
-rw-r--r--spec/models/ci/project_services/slack_service_spec.rb57
-rw-r--r--spec/models/ci/project_spec.rb246
-rw-r--r--spec/models/ci/runner_project_spec.rb2
-rw-r--r--spec/models/ci/runner_spec.rb10
-rw-r--r--spec/models/ci/service_spec.rb48
-rw-r--r--spec/models/ci/trigger_spec.rb4
-rw-r--r--spec/models/ci/variable_spec.rb2
-rw-r--r--spec/models/ci/web_hook_spec.rb63
-rw-r--r--spec/models/commit_range_spec.rb129
-rw-r--r--spec/models/commit_spec.rb34
-rw-r--r--spec/models/commit_status_spec.rb5
-rw-r--r--spec/models/concerns/case_sensitivity_spec.rb2
-rw-r--r--spec/models/concerns/strip_attribute_spec.rb20
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb57
-rw-r--r--spec/models/deploy_key_spec.rb2
-rw-r--r--spec/models/deploy_keys_project_spec.rb2
-rw-r--r--spec/models/event_spec.rb2
-rw-r--r--spec/models/external_issue_spec.rb2
-rw-r--r--spec/models/external_wiki_service_spec.rb2
-rw-r--r--spec/models/generic_commit_status_spec.rb2
-rw-r--r--spec/models/global_milestone_spec.rb2
-rw-r--r--spec/models/group_spec.rb2
-rw-r--r--spec/models/hooks/project_hook_spec.rb2
-rw-r--r--spec/models/hooks/service_hook_spec.rb2
-rw-r--r--spec/models/hooks/system_hook_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb8
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/key_spec.rb4
-rw-r--r--spec/models/label_link_spec.rb2
-rw-r--r--spec/models/label_spec.rb2
-rw-r--r--spec/models/member_spec.rb2
-rw-r--r--spec/models/members/group_member_spec.rb2
-rw-r--r--spec/models/members/project_member_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb93
-rw-r--r--spec/models/milestone_spec.rb2
-rw-r--r--spec/models/namespace_spec.rb2
-rw-r--r--spec/models/note_spec.rb29
-rw-r--r--spec/models/project_security_spec.rb2
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb2
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb2
-rw-r--r--spec/models/project_services/flowdock_service_spec.rb2
-rw-r--r--spec/models/project_services/gemnasium_service_spec.rb2
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb57
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb2
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb73
-rw-r--r--spec/models/project_services/irker_service_spec.rb2
-rw-r--r--spec/models/project_services/jira_service_spec.rb8
-rw-r--r--spec/models/project_services/pushover_service_spec.rb2
-rw-r--r--spec/models/project_services/slack_service/build_message_spec.rb46
-rw-r--r--spec/models/project_services/slack_service/issue_message_spec.rb2
-rw-r--r--spec/models/project_services/slack_service/merge_message_spec.rb2
-rw-r--r--spec/models/project_services/slack_service/note_message_spec.rb10
-rw-r--r--spec/models/project_services/slack_service/push_message_spec.rb2
-rw-r--r--spec/models/project_services/slack_service_spec.rb2
-rw-r--r--spec/models/project_snippet_spec.rb2
-rw-r--r--spec/models/project_spec.rb102
-rw-r--r--spec/models/project_team_spec.rb2
-rw-r--r--spec/models/project_wiki_spec.rb2
-rw-r--r--spec/models/protected_branch_spec.rb2
-rw-r--r--spec/models/repository_spec.rb121
-rw-r--r--spec/models/service_spec.rb2
-rw-r--r--spec/models/snippet_spec.rb2
-rw-r--r--spec/models/user_spec.rb25
-rw-r--r--spec/models/wiki_page_spec.rb2
-rw-r--r--spec/requests/api/groups_spec.rb59
-rw-r--r--spec/requests/api/labels_spec.rb10
-rw-r--r--spec/requests/api/merge_requests_spec.rb36
-rw-r--r--spec/requests/api/project_hooks_spec.rb12
-rw-r--r--spec/requests/api/projects_spec.rb91
-rw-r--r--spec/requests/api/services_spec.rb2
-rw-r--r--spec/requests/api/tags_spec.rb71
-rw-r--r--spec/requests/api/triggers_spec.rb80
-rw-r--r--spec/requests/api/users_spec.rb4
-rw-r--r--spec/requests/ci/api/builds_spec.rb40
-rw-r--r--spec/requests/ci/api/commits_spec.rb65
-rw-r--r--spec/requests/ci/api/projects_spec.rb232
-rw-r--r--spec/requests/ci/api/runners_spec.rb37
-rw-r--r--spec/requests/ci/api/triggers_spec.rb21
-rw-r--r--spec/services/archive_repository_service_spec.rb2
-rw-r--r--spec/services/ci/create_commit_service_spec.rb172
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb7
-rw-r--r--spec/services/ci/event_service_spec.rb34
-rw-r--r--spec/services/ci/image_for_build_service_spec.rb10
-rw-r--r--spec/services/ci/register_build_service_spec.rb12
-rw-r--r--spec/services/ci/web_hook_service_spec.rb37
-rw-r--r--spec/services/create_commit_builds_service_spec.rb175
-rw-r--r--spec/services/create_release_service_spec.rb34
-rw-r--r--spec/services/create_snippet_service_spec.rb2
-rw-r--r--spec/services/destroy_group_service_spec.rb2
-rw-r--r--spec/services/event_create_service_spec.rb2
-rw-r--r--spec/services/git_hooks_service_spec.rb53
-rw-r--r--spec/services/git_push_service_spec.rb2
-rw-r--r--spec/services/git_tag_push_service_spec.rb18
-rw-r--r--spec/services/issues/bulk_update_service_spec.rb2
-rw-r--r--spec/services/issues/close_service_spec.rb6
-rw-r--r--spec/services/issues/create_service_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb90
-rw-r--r--spec/services/merge_requests/close_service_spec.rb6
-rw-r--r--spec/services/merge_requests/create_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb12
-rw-r--r--spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb84
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb8
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb6
-rw-r--r--spec/services/merge_requests/update_service_spec.rb59
-rw-r--r--spec/services/milestones/close_service_spec.rb2
-rw-r--r--spec/services/milestones/create_service_spec.rb2
-rw-r--r--spec/services/notes/create_service_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb350
-rw-r--r--spec/services/projects/create_service_spec.rb9
-rw-r--r--spec/services/projects/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/download_service_spec.rb2
-rw-r--r--spec/services/projects/fork_service_spec.rb2
-rw-r--r--spec/services/projects/transfer_service_spec.rb2
-rw-r--r--spec/services/projects/update_service_spec.rb2
-rw-r--r--spec/services/projects/upload_service_spec.rb2
-rw-r--r--spec/services/search_service_spec.rb2
-rw-r--r--spec/services/system_hooks_service_spec.rb2
-rw-r--r--spec/services/system_note_service_spec.rb28
-rw-r--r--spec/services/test_hook_service_spec.rb2
-rw-r--r--spec/services/update_release_service_spec.rb34
-rw-r--r--spec/services/update_snippet_service_spec.rb4
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/support/filter_spec_helper.rb39
-rw-r--r--spec/support/markdown_feature.rb4
-rw-r--r--spec/support/matchers/markdown_matchers.rb14
-rw-r--r--spec/support/mentionable_shared_examples.rb23
-rw-r--r--spec/support/repo_helpers.rb12
-rw-r--r--spec/support/stub_gitlab_calls.rb4
-rw-r--r--spec/support/test_env.rb4
-rw-r--r--spec/support/wait_for_ajax.rb11
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb14
-rw-r--r--spec/workers/build_email_worker_spec.rb35
-rw-r--r--spec/workers/email_receiver_worker_spec.rb14
-rw-r--r--spec/workers/repository_fork_worker_spec.rb20
-rw-r--r--spec/workers/stuck_ci_builds_worker_spec.rb4
306 files changed, 5723 insertions, 4839 deletions
diff --git a/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb b/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
index 34cd9f7e4eb..3855763b200 100644
--- a/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
+++ b/spec/benchmarks/lib/gitlab/markdown/reference_filter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Markdown::ReferenceFilter, benchmark: true do
+describe Banzai::Filter::ReferenceFilter, benchmark: true do
let(:input) do
html = <<-EOF
<p>Hello @alice and @bob, how are you doing today?</p>
diff --git a/spec/controllers/abuse_reports_controller_spec.rb b/spec/controllers/abuse_reports_controller_spec.rb
index 0faab8d7ff0..15824a1c67f 100644
--- a/spec/controllers/abuse_reports_controller_spec.rb
+++ b/spec/controllers/abuse_reports_controller_spec.rb
@@ -18,27 +18,31 @@ describe AbuseReportsController do
end
it "sends a notification email" do
- post :create,
- abuse_report: {
- user_id: user.id,
- message: message
- }
-
- email = ActionMailer::Base.deliveries.last
-
- expect(email.to).to eq([admin_email])
- expect(email.subject).to include(user.username)
- expect(email.text_part.body).to include(message)
- end
-
- it "saves the abuse report" do
- expect do
+ perform_enqueued_jobs do
post :create,
abuse_report: {
user_id: user.id,
message: message
}
- end.to change { AbuseReport.count }.by(1)
+
+ email = ActionMailer::Base.deliveries.last
+
+ expect(email.to).to eq([admin_email])
+ expect(email.subject).to include(user.username)
+ expect(email.text_part.body).to include(message)
+ end
+ end
+
+ it "saves the abuse report" do
+ perform_enqueued_jobs do
+ expect do
+ post :create,
+ abuse_report: {
+ user_id: user.id,
+ message: message
+ }
+ end.to change { AbuseReport.count }.by(1)
+ end
end
end
diff --git a/spec/controllers/admin/impersonation_controller_spec.rb b/spec/controllers/admin/impersonation_controller_spec.rb
new file mode 100644
index 00000000000..d7a7ba1c5b6
--- /dev/null
+++ b/spec/controllers/admin/impersonation_controller_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Admin::ImpersonationController do
+ let(:admin) { create(:admin) }
+
+ before do
+ sign_in(admin)
+ end
+
+ describe 'CREATE #impersonation when blocked' do
+ let(:blocked_user) { create(:user, state: :blocked) }
+
+ it 'does not allow impersonation' do
+ post :create, id: blocked_user.username
+
+ expect(flash[:alert]).to eq 'You cannot impersonate a blocked user'
+ end
+ end
+end
diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb
index aa8d6cb807f..85379a8e984 100644
--- a/spec/controllers/autocomplete_controller_spec.rb
+++ b/spec/controllers/autocomplete_controller_spec.rb
@@ -114,7 +114,7 @@ describe AutocompleteController do
get(:users, project_id: project.id)
end
- it { expect(response.status).to eq(302) }
+ it { expect(response.status).to eq(404) }
end
describe 'GET #users with unknown project' do
@@ -122,7 +122,7 @@ describe AutocompleteController do
get(:users, project_id: 'unknown')
end
- it { expect(response.status).to eq(302) }
+ it { expect(response.status).to eq(404) }
end
describe 'GET #users with inaccessible group' do
@@ -131,7 +131,7 @@ describe AutocompleteController do
get(:users, group_id: user.namespace.id)
end
- it { expect(response.status).to eq(302) }
+ it { expect(response.status).to eq(404) }
end
describe 'GET #users with no project' do
@@ -139,7 +139,8 @@ describe AutocompleteController do
get(:users)
end
- it { expect(response.status).to eq(302) }
+ it { expect(body).to be_kind_of(Array) }
+ it { expect(body.size).to eq 0 }
end
end
end
diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb
index bb3d87f3840..7793bf1e421 100644
--- a/spec/controllers/commit_controller_spec.rb
+++ b/spec/controllers/commit_controller_spec.rb
@@ -69,6 +69,21 @@ describe Projects::CommitController do
expect(response.body).to start_with("diff --git")
end
+
+ it "should really only be a git diff without whitespace changes" do
+ get(:show,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: '66eceea0db202bb39c4e445e8ca28689645366c5',
+ # id: commit.id,
+ format: format,
+ w: 1)
+
+ expect(response.body).to start_with("diff --git")
+ # without whitespace option, there are more than 2 diff_splits
+ diff_splits = assigns(:diffs)[0].diff.split("\n")
+ expect(diff_splits.length).to be <= 2
+ end
end
describe "as patch" do
@@ -95,6 +110,26 @@ describe Projects::CommitController do
expect(response.body).to match(/^diff --git/)
end
end
+
+ context 'commit that removes a submodule' do
+ render_views
+
+ let(:fork_project) { create(:forked_project_with_submodules) }
+ let(:commit) { fork_project.commit('remove-submodule') }
+
+ before do
+ fork_project.team << [user, :master]
+ end
+
+ it 'renders it' do
+ get(:show,
+ namespace_id: fork_project.namespace.to_param,
+ project_id: fork_project.to_param,
+ id: commit.id)
+
+ expect(response).to be_success
+ end
+ end
end
describe "#branches" do
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
new file mode 100644
index 00000000000..eb0c6ac6d80
--- /dev/null
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Groups::MilestonesController do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+ let(:project2) { create(:empty_project, group: group) }
+ let(:user) { create(:user) }
+ let(:title) { '肯定不是中文的问题' }
+
+ before do
+ sign_in(user)
+ group.add_owner(user)
+ project.team << [user, :master]
+ controller.instance_variable_set(:@group, group)
+ end
+
+ describe "#create" do
+ it "should create group milestone with Chinese title" do
+ post :create,
+ group_id: group.id,
+ milestone: { project_ids: [project.id, project2.id], title: title }
+
+ expect(response).to redirect_to(group_milestone_path(group, title.to_slug.to_s, title: title))
+ expect(Milestone.where(title: title).count).to eq(2)
+ end
+ end
+end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 3e5e1fa87ae..6aaec224f6e 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -10,6 +10,30 @@ describe Projects::MergeRequestsController do
project.team << [user, :master]
end
+ describe '#new' do
+ context 'merge request that removes a submodule' do
+ render_views
+
+ let(:fork_project) { create(:forked_project_with_submodules) }
+
+ before do
+ fork_project.team << [user, :master]
+ end
+
+ it 'renders it' do
+ get :new,
+ namespace_id: fork_project.namespace.to_param,
+ project_id: fork_project.to_param,
+ merge_request: {
+ source_branch: 'remove-submodule',
+ target_branch: 'master'
+ }
+
+ expect(response).to be_success
+ end
+ end
+ end
+
describe "#show" do
shared_examples "export merge as" do |format|
it "should generally work" do
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 8127efabe6e..d173bb350f1 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -5,7 +5,7 @@ describe Projects::MilestonesController do
let(:user) { create(:user) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project, milestone: milestone) }
- let(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
before do
sign_in(user)
@@ -15,10 +15,9 @@ describe Projects::MilestonesController do
describe "#destroy" do
it "should remove milestone" do
- merge_request.reload
expect(issue.milestone_id).to eq(milestone.id)
- delete :destroy, namespace_id: project.namespace.id, project_id: project.id, id: milestone.id, format: :js
+ delete :destroy, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid, format: :js
expect(response).to be_success
expect(Event.first.action).to eq(Event::DESTROYED)
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index c114f342021..1caa476d37d 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -33,5 +33,39 @@ describe Projects::RawController do
expect(response.header['Content-Type']).to eq('image/jpeg')
end
end
+
+ context 'lfs object' do
+ let(:id) { 'be93687/files/lfs/lfs_object.iso' }
+ let!(:lfs_object) { create(:lfs_object, oid: '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897', size: '1575078') }
+
+ context 'when project has access' do
+ before do
+ public_project.lfs_objects << lfs_object
+ allow_any_instance_of(LfsObjectUploader).to receive(:exists?).and_return(true)
+ allow(controller).to receive(:send_file) { controller.render nothing: true }
+ end
+
+ it 'serves the file' do
+ expect(controller).to receive(:send_file).with("#{Gitlab.config.shared.path}/lfs-objects/91/ef/f75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897", filename: "lfs_object.iso", disposition: 'attachment')
+ get(:show,
+ namespace_id: public_project.namespace.to_param,
+ project_id: public_project.to_param,
+ id: id)
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context 'when project does not have access' do
+ it 'does not serve the file' do
+ get(:show,
+ namespace_id: public_project.namespace.to_param,
+ project_id: public_project.to_param,
+ id: id)
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 4bb47c6b025..665526fde93 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -88,6 +88,22 @@ describe ProjectsController do
end
end
+ describe "#destroy" do
+ let(:admin) { create(:admin) }
+
+ it "redirects to the dashboard" do
+ controller.instance_variable_set(:@project, project)
+ sign_in(admin)
+
+ orig_id = project.id
+ delete :destroy, namespace_id: project.namespace.path, id: project.path
+
+ expect { Project.find(orig_id) }.to raise_error(ActiveRecord::RecordNotFound)
+ expect(response.status).to eq(302)
+ expect(response).to redirect_to(dashboard_projects_path)
+ end
+ end
+
describe "POST #toggle_star" do
it "toggles star if user is signed in" do
sign_in(user)
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index e9b823c523c..b3dcb52c500 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -115,4 +115,119 @@ describe SnippetsController do
end
end
end
+
+ describe 'GET #raw' do
+ let(:user) { create(:user) }
+
+ context 'when the personal snippet is private' do
+ let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ context 'when signed in user is not the author' do
+ let(:other_author) { create(:author) }
+ let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
+
+ it 'responds with status 404' do
+ get :raw, id: other_personal_snippet.to_param
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when signed in user is the author' do
+ it 'renders the raw snippet' do
+ get :raw, id: personal_snippet.to_param
+
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get :raw, id: personal_snippet.to_param
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+
+ context 'when the personal snippet is internal' do
+ let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders the raw snippet' do
+ get :raw, id: personal_snippet.to_param
+
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get :raw, id: personal_snippet.to_param
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+
+ context 'when the personal snippet is public' do
+ let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ it 'renders the raw snippet' do
+ get :raw, id: personal_snippet.to_param
+
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context 'when not signed in' do
+ it 'renders the raw snippet' do
+ get :raw, id: personal_snippet.to_param
+
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ context 'when the personal snippet does not exist' do
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ it 'responds with status 404' do
+ get :raw, id: 'doesntexist'
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when not signed in' do
+ it 'responds with status 404' do
+ get :raw, id: 'doesntexist'
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+ end
end
diff --git a/spec/factories.rb b/spec/factories.rb
index 4bf93adabe2..d6b4efa9a03 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -43,7 +43,8 @@ FactoryGirl.define do
end
after(:create) do |user, evaluator|
- user.identities << create(:identity,
+ user.identities << create(
+ :identity,
provider: evaluator.provider,
extern_uid: evaluator.extern_uid
)
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 2fcd70182b9..f76e826f138 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -42,6 +42,10 @@ FactoryGirl.define do
commit factory: :ci_commit
+ after(:build) do |build, evaluator|
+ build.project = build.commit.project
+ end
+
factory :ci_not_started_build do
started_at nil
finished_at nil
diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb
index 79e000b7ccb..b42cafa518a 100644
--- a/spec/factories/ci/commits.rb
+++ b/spec/factories/ci/commits.rb
@@ -2,17 +2,18 @@
#
# Table name: commits
#
-# id :integer not null, primary key
-# project_id :integer
-# ref :string(255)
-# sha :string(255)
-# before_sha :string(255)
-# push_data :text
-# created_at :datetime
-# updated_at :datetime
-# tag :boolean default(FALSE)
-# yaml_errors :text
-# committed_at :datetime
+# id :integer not null, primary key
+# project_id :integer
+# ref :string(255)
+# sha :string(255)
+# before_sha :string(255)
+# push_data :text
+# created_at :datetime
+# updated_at :datetime
+# tag :boolean default(FALSE)
+# yaml_errors :text
+# committed_at :datetime
+# gl_project_id :integer
#
# Read about factories at https://github.com/thoughtbot/factory_girl
@@ -20,7 +21,7 @@ FactoryGirl.define do
factory :ci_empty_commit, class: Ci::Commit do
sha '97de212e80737a608d939f648d959671fb0a0142'
- gl_project factory: :empty_project
+ project factory: :empty_project
factory :ci_commit_without_jobs do
after(:build) do |commit|
diff --git a/spec/factories/ci/events.rb b/spec/factories/ci/events.rb
deleted file mode 100644
index 9638618a400..00000000000
--- a/spec/factories/ci/events.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# == Schema Information
-#
-# Table name: events
-#
-# id :integer not null, primary key
-# project_id :integer
-# user_id :integer
-# is_admin :integer
-# description :text
-# created_at :datetime
-# updated_at :datetime
-#
-
-FactoryGirl.define do
- factory :ci_event, class: Ci::Event do
- sequence :description do |n|
- "updated project settings#{n}"
- end
-
- factory :ci_admin_event do
- is_admin true
- end
- end
-end
diff --git a/spec/factories/ci/projects.rb b/spec/factories/ci/projects.rb
deleted file mode 100644
index 11cb8c9eeaa..00000000000
--- a/spec/factories/ci/projects.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# == Schema Information
-#
-# Table name: projects
-#
-# id :integer not null, primary key
-# name :string(255) not null
-# timeout :integer default(3600), not null
-# created_at :datetime
-# updated_at :datetime
-# token :string(255)
-# default_ref :string(255)
-# path :string(255)
-# always_build :boolean default(FALSE), not null
-# polling_interval :integer
-# public :boolean default(FALSE), not null
-# ssh_url_to_repo :string(255)
-# gitlab_id :integer
-# allow_git_fetch :boolean default(TRUE), not null
-# email_recipients :string(255) default(""), not null
-# email_add_pusher :boolean default(TRUE), not null
-# email_only_broken_builds :boolean default(TRUE), not null
-# skip_refs :string(255)
-# coverage_regex :string(255)
-# shared_runners_enabled :boolean default(FALSE)
-# generated_yaml_config :text
-#
-
-# Read about factories at https://github.com/thoughtbot/factory_girl
-
-FactoryGirl.define do
- factory :ci_project_without_token, class: Ci::Project do
- default_ref 'master'
-
- shared_runners_enabled false
-
- factory :ci_project do
- token 'iPWx6WM4lhHNedGfBpPJNP'
- end
-
- initialize_with do
- # TODO:
- # this is required, because builds_enabled is initialized when Project is created
- # and this create gitlab_ci_project if builds is set to true
- # here we take created gitlab_ci_project and update it's attributes
- ci_project = create(:empty_project).ensure_gitlab_ci_project
- ci_project.update_attributes(attributes)
- ci_project
- end
- end
-end
diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb
index 3aa14ca434d..008d1c5d961 100644
--- a/spec/factories/ci/runner_projects.rb
+++ b/spec/factories/ci/runner_projects.rb
@@ -14,6 +14,6 @@
FactoryGirl.define do
factory :ci_runner_project, class: Ci::RunnerProject do
runner_id 1
- project_id 1
+ gl_project_id 1
end
end
diff --git a/spec/factories/ci/web_hook.rb b/spec/factories/ci/web_hook.rb
deleted file mode 100644
index 40d878ecb3c..00000000000
--- a/spec/factories/ci/web_hook.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-FactoryGirl.define do
- factory :ci_web_hook, class: Ci::WebHook do
- sequence(:url) { FFaker::Internet.uri('http') }
- project factory: :ci_project
- end
-end
diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb
index 52de437052d..8898b71e2a3 100644
--- a/spec/factories/commit_statuses.rb
+++ b/spec/factories/commit_statuses.rb
@@ -5,7 +5,7 @@ FactoryGirl.define do
name 'default'
status 'success'
description 'commit status'
- commit factory: :ci_commit
+ commit factory: :ci_commit_with_one_job
factory :generic_commit_status, class: GenericCommitStatus do
name 'generic'
diff --git a/spec/factories/lfs_objects.rb b/spec/factories/lfs_objects.rb
index 7fb2d77ca32..2da107ba24b 100644
--- a/spec/factories/lfs_objects.rb
+++ b/spec/factories/lfs_objects.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: lfs_objects
+#
+# id :integer not null, primary key
+# oid :string(255) not null
+# size :integer not null
+# created_at :datetime
+# updated_at :datetime
+# file :string(255)
+#
+
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
diff --git a/spec/factories/lfs_objects_projects.rb b/spec/factories/lfs_objects_projects.rb
index 93de6607df8..3772236a77a 100644
--- a/spec/factories/lfs_objects_projects.rb
+++ b/spec/factories/lfs_objects_projects.rb
@@ -1,3 +1,14 @@
+# == Schema Information
+#
+# Table name: lfs_objects_projects
+#
+# id :integer not null, primary key
+# lfs_object_id :integer not null
+# project_id :integer not null
+# created_at :datetime
+# updated_at :datetime
+#
+
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 729a49c9f72..5b4d7f41bc4 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -65,6 +65,11 @@ FactoryGirl.define do
target_branch "master"
end
+ trait :merge_when_build_succeeds do
+ merge_when_build_succeeds true
+ merge_user author
+ end
+
factory :closed_merge_request, traits: [:closed]
factory :reopened_merge_request, traits: [:reopened]
factory :merge_request_with_diffs, traits: [:with_diffs]
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 9d777ddfccd..35a20adeef3 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -16,6 +16,7 @@
# system :boolean default(FALSE), not null
# st_diff :text
# updated_by_id :integer
+# is_award :boolean default(FALSE), not null
#
require_relative '../support/repo_helpers'
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 1d500a11ad7..112213377ff 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -28,6 +28,7 @@
# import_type :string(255)
# import_source :string(255)
# commit_count :integer default(0)
+# import_error :text
#
FactoryGirl.define do
diff --git a/spec/features/ci/admin/builds_spec.rb b/spec/features/admin/admin_builds_spec.rb
index 623d466c67b..72764b1629d 100644
--- a/spec/features/ci/admin/builds_spec.rb
+++ b/spec/features/admin/admin_builds_spec.rb
@@ -5,17 +5,16 @@ describe "Admin Builds" do
let(:build) { FactoryGirl.create :ci_build, commit: commit }
before do
- skip_ci_admin_auth
- login_as :user
+ login_as :admin
end
describe "GET /admin/builds" do
before do
build
- visit ci_admin_builds_path
+ visit admin_builds_path
end
- it { expect(page).to have_content "All builds" }
+ it { expect(page).to have_content "Running" }
it { expect(page).to have_content build.short_sha }
end
@@ -26,43 +25,43 @@ describe "Admin Builds" do
FactoryGirl.create :ci_build, commit: commit, status: "success"
FactoryGirl.create :ci_build, commit: commit, status: "failed"
- visit ci_admin_builds_path
+ visit admin_builds_path
+
+ within ".center-top-menu" do
+ click_on "All"
+ end
expect(page.all(".build-link").size).to eq(4)
end
- it "shows pending builds" do
+ it "shows finished builds" do
build = FactoryGirl.create :ci_build, commit: commit, status: "pending"
build1 = FactoryGirl.create :ci_build, commit: commit, status: "running"
build2 = FactoryGirl.create :ci_build, commit: commit, status: "success"
- build3 = FactoryGirl.create :ci_build, commit: commit, status: "failed"
- visit ci_admin_builds_path
+ visit admin_builds_path
- within ".nav.nav-tabs" do
- click_on "Pending"
+ within ".center-top-menu" do
+ click_on "Finished"
end
- expect(page.find(".build-link")).to have_content(build.id)
+ expect(page.find(".build-link")).not_to have_content(build.id)
expect(page.find(".build-link")).not_to have_content(build1.id)
- expect(page.find(".build-link")).not_to have_content(build2.id)
- expect(page.find(".build-link")).not_to have_content(build3.id)
+ expect(page.find(".build-link")).to have_content(build2.id)
end
it "shows running builds" do
build = FactoryGirl.create :ci_build, commit: commit, status: "pending"
- build1 = FactoryGirl.create :ci_build, commit: commit, status: "running"
build2 = FactoryGirl.create :ci_build, commit: commit, status: "success"
build3 = FactoryGirl.create :ci_build, commit: commit, status: "failed"
- visit ci_admin_builds_path
+ visit admin_builds_path
- within ".nav.nav-tabs" do
+ within ".center-top-menu" do
click_on "Running"
end
- expect(page.find(".build-link")).to have_content(build1.id)
- expect(page.find(".build-link")).not_to have_content(build.id)
+ expect(page.find(".build-link")).to have_content(build.id)
expect(page.find(".build-link")).not_to have_content(build2.id)
expect(page.find(".build-link")).not_to have_content(build3.id)
end
diff --git a/spec/features/ci/admin/runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index b83744f53a8..66a2cc0c157 100644
--- a/spec/features/ci/admin/runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -10,7 +10,7 @@ describe "Admin Runners" do
runner = FactoryGirl.create(:ci_runner)
commit = FactoryGirl.create(:ci_commit)
FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id)
- visit ci_admin_runners_path
+ visit admin_runners_path
end
it { page.has_text? "Manage Runners" }
@@ -36,9 +36,9 @@ describe "Admin Runners" do
let(:runner) { FactoryGirl.create :ci_runner }
before do
- @project1 = FactoryGirl.create(:ci_project)
- @project2 = FactoryGirl.create(:ci_project)
- visit ci_admin_runner_path(runner)
+ @project1 = FactoryGirl.create(:empty_project)
+ @project2 = FactoryGirl.create(:empty_project)
+ visit admin_runner_path(runner)
end
describe 'runner info' do
@@ -53,7 +53,7 @@ describe "Admin Runners" do
describe 'search' do
before do
search_form = find('#runner-projects-search')
- search_form.fill_in 'search', with: @project1.gl_project.name
+ search_form.fill_in 'search', with: @project1.name
search_form.click_button 'Search'
end
@@ -61,4 +61,26 @@ describe "Admin Runners" do
it { expect(page).not_to have_content(@project2.name_with_namespace) }
end
end
+
+ describe 'runners registration token' do
+ let!(:token) { current_application_settings.ensure_runners_registration_token }
+ before { visit admin_runners_path }
+
+ it 'has a registration token' do
+ expect(page).to have_content("Registration token is #{token}")
+ expect(page).to have_selector('#runners-token', text: token)
+ end
+
+ describe 'reload registration token' do
+ let(:page_token) { find('#runners-token').text }
+
+ before do
+ click_button 'Reset runners registration token'
+ end
+
+ it 'changes registration token' do
+ expect(page_token).to_not eq token
+ end
+ end
+ end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 4c756a8e732..4570e409128 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -87,13 +87,16 @@ describe "Admin::Users", feature: true do
end
it "should call send mail" do
- expect(Notify).to receive(:new_user_email)
+ expect_any_instance_of(NotificationService).to receive(:new_user)
click_button "Create user"
end
it "should send valid email to user with email & password" do
- click_button "Create user"
+ perform_enqueued_jobs do
+ click_button "Create user"
+ end
+
user = User.find_by(username: 'bang')
email = ActionMailer::Base.deliveries.last
expect(email.subject).to have_content('Account was created')
@@ -125,6 +128,16 @@ describe "Admin::Users", feature: true do
expect(page).not_to have_content('Impersonate')
end
+
+ it 'should not show impersonate button for blocked user' do
+ another_user.block
+
+ visit admin_user_path(another_user)
+
+ expect(page).not_to have_content('Impersonate')
+
+ another_user.activate
+ end
end
context 'when impersonating' do
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index 5213ce1099f..f0031a0a247 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -7,19 +7,19 @@ describe "Builds" do
login_as(:user)
@commit = FactoryGirl.create :ci_commit
@build = FactoryGirl.create :ci_build, commit: @commit
- @gl_project = @commit.project.gl_project
- @gl_project.team << [@user, :master]
+ @project = @commit.project
+ @project.team << [@user, :master]
end
describe "GET /:project/builds" do
context "Running scope" do
before do
@build.run!
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
+ visit namespace_project_builds_path(@project.namespace, @project)
end
it { expect(page).to have_content 'Running' }
- it { expect(page).to have_content 'Cancel all' }
+ it { expect(page).to have_content 'Cancel running' }
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
@@ -28,41 +28,41 @@ describe "Builds" do
context "Finished scope" do
before do
@build.run!
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :finished)
+ visit namespace_project_builds_path(@project.namespace, @project, scope: :finished)
end
it { expect(page).to have_content 'No builds to show' }
- it { expect(page).to have_content 'Cancel all' }
+ it { expect(page).to have_content 'Cancel running' }
end
context "All builds" do
before do
- @gl_project.ci_builds.running_or_pending.each(&:success)
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :all)
+ @project.builds.running_or_pending.each(&:success)
+ visit namespace_project_builds_path(@project.namespace, @project, scope: :all)
end
it { expect(page).to have_content 'All' }
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
- it { expect(page).to_not have_content 'Cancel all' }
+ it { expect(page).to_not have_content 'Cancel running' }
end
end
describe "POST /:project/builds/:id/cancel_all" do
before do
@build.run!
- visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
- click_link "Cancel all"
+ visit namespace_project_builds_path(@project.namespace, @project)
+ click_link "Cancel running"
end
it { expect(page).to have_content 'No builds to show' }
- it { expect(page).to_not have_content 'Cancel all' }
+ it { expect(page).to_not have_content 'Cancel running' }
end
describe "GET /:project/builds/:id" do
before do
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
end
it { expect(page).to have_content @commit.sha[0..7] }
@@ -72,7 +72,7 @@ describe "Builds" do
context "Download artifacts" do
before do
@build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
end
it { expect(page).to have_content 'Download artifacts' }
@@ -82,7 +82,7 @@ describe "Builds" do
describe "POST /:project/builds/:id/cancel" do
before do
@build.run!
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
click_link "Cancel"
end
@@ -93,7 +93,7 @@ describe "Builds" do
describe "POST /:project/builds/:id/retry" do
before do
@build.run!
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
click_link "Cancel"
click_link 'Retry'
end
@@ -105,7 +105,7 @@ describe "Builds" do
describe "GET /:project/builds/:id/download" do
before do
@build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
click_link 'Download artifacts'
end
diff --git a/spec/features/ci/admin/events_spec.rb b/spec/features/ci/admin/events_spec.rb
deleted file mode 100644
index a7e75cc4f6b..00000000000
--- a/spec/features/ci/admin/events_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'spec_helper'
-
-describe "Admin Events" do
- let(:event) { FactoryGirl.create :ci_admin_event }
-
- before do
- skip_ci_admin_auth
- login_as :user
- end
-
- describe "GET /admin/events" do
- before do
- event
- visit ci_admin_events_path
- end
-
- it { expect(page).to have_content "Events" }
- it { expect(page).to have_content event.description }
- end
-end
diff --git a/spec/features/ci/admin/projects_spec.rb b/spec/features/ci/admin/projects_spec.rb
deleted file mode 100644
index b88f55a6807..00000000000
--- a/spec/features/ci/admin/projects_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-
-describe "Admin Projects" do
- let(:project) { FactoryGirl.create :ci_project }
-
- before do
- skip_ci_admin_auth
- login_as :user
- end
-
- describe "GET /admin/projects" do
- before do
- project
- visit ci_admin_projects_path
- end
-
- it { expect(page).to have_content "Projects" }
- end
-end
diff --git a/spec/features/ci_settings_spec.rb b/spec/features/ci_settings_spec.rb
deleted file mode 100644
index 7e25e883018..00000000000
--- a/spec/features/ci_settings_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-
-describe "CI settings" do
- let(:user) { create(:user) }
- before { login_as(user) }
-
- before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
- visit edit_namespace_project_ci_settings_path(@gl_project.namespace, @gl_project)
- end
-
- it { expect(page).to have_content 'Build Schedule' }
-
- it "updates configuration" do
- fill_in 'Timeout', with: '70'
- click_button 'Save changes'
- expect(page).to have_content 'was successfully updated'
- expect(find_field('Timeout').value).to eq '70'
- end
-end
diff --git a/spec/features/ci_web_hooks_spec.rb b/spec/features/ci_web_hooks_spec.rb
deleted file mode 100644
index efae0a42c1e..00000000000
--- a/spec/features/ci_web_hooks_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require 'spec_helper'
-
-describe 'CI web hooks' do
- let(:user) { create(:user) }
- before { login_as(user) }
-
- before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
- visit namespace_project_ci_web_hooks_path(@gl_project.namespace, @gl_project)
- end
-
- context 'create a trigger' do
- before do
- fill_in 'web_hook_url', with: 'http://example.com'
- click_on 'Add Web Hook'
- end
-
- it { expect(@project.web_hooks.count).to eq(1) }
-
- it 'revokes the trigger' do
- click_on 'Remove'
- expect(@project.web_hooks.count).to eq(0)
- end
- end
-end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 90739cd6a28..fe7f07f5b75 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -1,74 +1,99 @@
require 'spec_helper'
-describe "Commits" do
+describe 'Commits' do
include CiStatusHelper
let(:project) { create(:project) }
- describe "CI" do
+ describe 'CI' do
before do
login_as :user
project.team << [@user, :master]
- @ci_project = project.ensure_gitlab_ci_project
- @commit = FactoryGirl.create :ci_commit, gl_project: project, sha: project.commit.sha
- @build = FactoryGirl.create :ci_build, commit: @commit
- @generic_status = FactoryGirl.create :generic_commit_status, commit: @commit
+ stub_ci_commit_to_return_yaml_file
end
- before do
- stub_ci_commit_to_return_yaml_file
+ let!(:commit) do
+ FactoryGirl.create :ci_commit, project: project, sha: project.commit.sha
+ end
+
+ let!(:build) { FactoryGirl.create :ci_build, commit: commit }
+
+ describe 'Project commits' do
+ before do
+ visit namespace_project_commits_path(project.namespace, project, :master)
+ end
+
+ it 'should show build status' do
+ page.within("//li[@id='commit-#{commit.short_sha}']") do
+ expect(page).to have_css(".ci-status-link")
+ end
+ end
end
- describe "GET /:project/commits/:sha/ci" do
+ describe 'Commit builds' do
before do
- visit ci_status_path(@commit)
+ visit ci_status_path(commit)
end
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
+ it { expect(page).to have_content commit.sha[0..7] }
+ it { expect(page).to have_content commit.git_commit_message }
+ it { expect(page).to have_content commit.git_author_name }
end
- context "Download artifacts" do
+ context 'Download artifacts' do
let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
before do
- @build.update_attributes(artifacts_file: artifacts_file)
+ build.update_attributes(artifacts_file: artifacts_file)
end
it do
- visit ci_status_path(@commit)
- click_on "Download artifacts"
+ visit ci_status_path(commit)
+ click_on 'Download artifacts'
expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type)
end
end
- describe "Cancel all builds" do
- it "cancels commit" do
- visit ci_status_path(@commit)
- click_on "Cancel running"
- expect(page).to have_content "canceled"
+ describe 'Cancel all builds' do
+ it 'cancels commit' do
+ visit ci_status_path(commit)
+ click_on 'Cancel running'
+ expect(page).to have_content 'canceled'
end
end
- describe "Cancel build" do
- it "cancels build" do
- visit ci_status_path(@commit)
- click_on "Cancel"
- expect(page).to have_content "canceled"
+ describe 'Cancel build' do
+ it 'cancels build' do
+ visit ci_status_path(commit)
+ click_on 'Cancel'
+ expect(page).to have_content 'canceled'
end
end
- describe ".gitlab-ci.yml not found warning" do
- it "does not show warning" do
- visit ci_status_path(@commit)
- expect(page).not_to have_content ".gitlab-ci.yml not found in this commit"
+ describe '.gitlab-ci.yml not found warning' do
+ context 'ci builds enabled' do
+ it "does not show warning" do
+ visit ci_status_path(commit)
+ expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ end
+
+ it 'shows warning' do
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(commit)
+ expect(page).to have_content '.gitlab-ci.yml not found in this commit'
+ end
end
- it "shows warning" do
- stub_ci_commit_yaml_file(nil)
- visit ci_status_path(@commit)
- expect(page).to have_content ".gitlab-ci.yml not found in this commit"
+ context 'ci builds disabled' do
+ before do
+ stub_ci_builds_disabled
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(commit)
+ end
+
+ it 'does not show warning' do
+ expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
+ end
end
end
end
diff --git a/spec/features/issues/filter_by_milestone_spec.rb b/spec/features/issues/filter_by_milestone_spec.rb
index f600f8684ac..38c8d343ce3 100644
--- a/spec/features/issues/filter_by_milestone_spec.rb
+++ b/spec/features/issues/filter_by_milestone_spec.rb
@@ -13,7 +13,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(Milestone::None.title)
- expect(page).to have_css('.issue-title', count: 1)
+ expect(page).to have_css('.title', count: 1)
end
scenario 'filters by a specific Milestone', js: true do
@@ -23,7 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do
visit_issues(project)
filter_by_milestone(milestone.title)
- expect(page).to have_css('.issue-title', count: 1)
+ expect(page).to have_css('.title', count: 1)
end
def visit_issues(project)
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
new file mode 100644
index 00000000000..e4efdbe2421
--- /dev/null
+++ b/spec/features/issues/note_polling_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+feature 'Issue notes polling' do
+ let!(:project) { create(:project, :public) }
+ let!(:issue) { create(:issue, project: project) }
+
+ background do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ scenario 'Another user adds a comment to an issue', js: true do
+ note = create(:note_on_issue, noteable: issue, note: 'Looks good!')
+ page.execute_script('notes.refresh();')
+ expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
+ end
+end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 32fd4065bb4..a2fb3e4c75d 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -61,7 +61,7 @@ describe 'Issues', feature: true do
it 'allows user to select unasigned', js: true do
visit edit_namespace_project_issue_path(project.namespace, project, issue)
- expect(page).to have_content "Assign to #{@user.name}"
+ expect(page).to have_content "Assignee #{@user.name}"
first('#s2id_issue_assignee_id').click
sleep 2 # wait for ajax stuff to complete
@@ -69,7 +69,10 @@ describe 'Issues', feature: true do
click_button 'Save changes'
- expect(page).to have_content 'Assignee: none'
+ page.within('.assignee') do
+ expect(page).to have_content 'None'
+ end
+
expect(issue.reload.assignee).to be_nil
end
end
@@ -202,11 +205,11 @@ describe 'Issues', feature: true do
it 'with dropdown menu' do
visit namespace_project_issue_path(project.namespace, project, issue)
- find('.context #issue_assignee_id').
+ find('.issuable-sidebar #issue_assignee_id').
set project.team.members.first.id
click_button 'Update Issue'
- expect(page).to have_content 'Assignee:'
+ expect(page).to have_content 'Assignee'
has_select?('issue_assignee_id',
selected: project.team.members.first.name)
end
@@ -241,12 +244,16 @@ describe 'Issues', feature: true do
it 'with dropdown menu' do
visit namespace_project_issue_path(project.namespace, project, issue)
- find('.context').
+ find('.issuable-sidebar').
select(milestone.title, from: 'issue_milestone_id')
click_button 'Update Issue'
expect(page).to have_content "Milestone changed to #{milestone.title}"
- expect(page).to have_content "Milestone: #{milestone.title}"
+
+ page.within('.milestone') do
+ expect(page).to have_content milestone.title
+ end
+
has_select?('issue_assignee_id', selected: milestone.title)
end
end
@@ -279,13 +286,19 @@ describe 'Issues', feature: true do
it 'allows user to remove assignee', js: true do
visit namespace_project_issue_path(project.namespace, project, issue)
- expect(page).to have_content "Assignee: #{user2.name}"
- first('#s2id_issue_assignee_id').click
+ page.within('.assignee') do
+ expect(page).to have_content user2.name
+ end
+
+ find('.assignee .edit-link').click
sleep 2 # wait for ajax stuff to complete
first('.user-result').click
- expect(page).to have_content 'Assignee: none'
+ page.within('.assignee') do
+ expect(page).to have_content 'None'
+ end
+
sleep 2 # wait for ajax stuff to complete
expect(issue.reload.assignee).to be_nil
end
@@ -293,10 +306,10 @@ describe 'Issues', feature: true do
end
def first_issue
- page.all('ul.issues-list li').first.text
+ page.all('ul.issues-list > li').first.text
end
def last_issue
- page.all('ul.issues-list li').last.text
+ page.all('ul.issues-list > li').last.text
end
end
diff --git a/spec/features/ci/lint_spec.rb b/spec/features/lint_spec.rb
index 5d8f56e2cfb..5d8f56e2cfb 100644
--- a/spec/features/ci/lint_spec.rb
+++ b/spec/features/lint_spec.rb
diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
new file mode 100644
index 00000000000..7aa7eb965e9
--- /dev/null
+++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
@@ -0,0 +1,85 @@
+require 'spec_helper'
+
+feature 'Merge When Build Succeeds', feature: true, js: true do
+ 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") }
+
+ before do
+ project.team << [user, :master]
+ project.enable_ci
+ end
+
+ context "Active build for Merge Request" do
+ let!(:ci_commit) { create(:ci_commit, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+ let!(:ci_build) { create(:ci_build, commit: ci_commit) }
+
+ before do
+ login_as user
+ visit_merge_request(merge_request)
+ end
+
+ it 'displays the Merge When Build Succeeds button' do
+ expect(page).to have_button "Merge When Build Succeeds"
+ end
+
+ context "Merge When Build succeeds enabled" do
+ before do
+ click_button "Merge When Build Succeeds"
+ end
+
+ it 'activates Merge When Build Succeeds feature' do
+ expect(page).to have_link "Cancel Automatic Merge"
+
+ expect(page).to have_content "Set by #{user.name} to be merged automatically when the build succeeds."
+ expect(page).to have_content "The source branch will not be removed."
+
+ visit_merge_request(merge_request) # Needed to refresh the page
+ expect(page).to have_content /Enabled an automatic merge when the build for [0-9a-f]{8} succeeds/i
+ end
+ end
+ end
+
+ context 'When it is enabled' do
+ let(:merge_request) do
+ create(:merge_request_with_diffs, :simple, source_project: project, author: user,
+ merge_user: user, title: "MepMep", merge_when_build_succeeds: true)
+ end
+
+ let!(:ci_commit) { create(:ci_commit, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+ let!(:ci_build) { create(:ci_build, commit: ci_commit) }
+
+ before do
+ login_as user
+ visit_merge_request(merge_request)
+ end
+
+ it 'cancels the automatic merge' do
+ click_link "Cancel Automatic Merge"
+
+ expect(page).to have_button "Merge When Build Succeeds"
+
+ visit_merge_request(merge_request) # Needed to refresh the page
+ expect(page).to have_content "Canceled the automatic merge"
+ end
+
+ it "allows the user to remove the source branch" do
+ expect(page).to have_link "Remove Source Branch When Merged"
+
+ click_link "Remove Source Branch When Merged"
+ expect(page).to have_content "The source branch will be removed"
+ end
+ end
+
+ context 'Build is not active' do
+ it "should not allow for enabling" do
+ visit_merge_request(merge_request)
+ expect(page).not_to have_link "Merge When Build Succeeds"
+ end
+ end
+
+ def visit_merge_request(merge_request)
+ visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ end
+end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index d7cb3b2e86e..f0fc6916c4d 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
describe 'Comments', feature: true do
include RepoHelpers
+ include WaitForAjax
describe 'On a merge request', js: true, feature: true do
let!(:merge_request) { create(:merge_request) }
@@ -123,8 +124,8 @@ describe 'Comments', feature: true do
it 'removes the attachment div and resets the edit form' do
find('.js-note-attachment-delete').click
is_expected.not_to have_css('.note-attachment')
- expect(find('.current-note-edit-form', visible: false)).
- not_to be_visible
+ is_expected.not_to have_css('.current-note-edit-form')
+ wait_for_ajax
end
end
end
diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb
index 85e70b4d47f..257d363438c 100644
--- a/spec/features/password_reset_spec.rb
+++ b/spec/features/password_reset_spec.rb
@@ -3,11 +3,12 @@ require 'spec_helper'
feature 'Password reset', feature: true do
describe 'throttling' do
it 'sends reset instructions when not previously sent' do
- visit root_path
- forgot_password(create(:user))
+ user = create(:user)
+ forgot_password(user)
- expect(page).to have_content(I18n.t('devise.passwords.send_instructions'))
+ expect(page).to have_content(I18n.t('devise.passwords.send_paranoid_instructions'))
expect(current_path).to eq new_user_session_path
+ expect(user.recently_sent_password_reset?).to be_truthy
end
it 'sends reset instructions when previously sent more than a minute ago' do
@@ -15,26 +16,25 @@ feature 'Password reset', feature: true do
user.send_reset_password_instructions
user.update_attribute(:reset_password_sent_at, 5.minutes.ago)
- visit root_path
- forgot_password(user)
-
- expect(page).to have_content(I18n.t('devise.passwords.send_instructions'))
+ expect{ forgot_password(user) }.to change{ user.reset_password_sent_at }
+ expect(page).to have_content(I18n.t('devise.passwords.send_paranoid_instructions'))
expect(current_path).to eq new_user_session_path
end
- it "throttles multiple resets in a short timespan" do
+ it 'throttles multiple resets in a short timespan' do
user = create(:user)
user.send_reset_password_instructions
+ # Reload because PG handles datetime less precisely than Ruby/Rails
+ user.reload
- visit root_path
- forgot_password(user)
-
- expect(page).to have_content(I18n.t('devise.passwords.recently_reset'))
- expect(current_path).to eq new_user_password_path
+ expect{ forgot_password(user) }.not_to change{ user.reset_password_sent_at }
+ expect(page).to have_content(I18n.t('devise.passwords.send_paranoid_instructions'))
+ expect(current_path).to eq new_user_session_path
end
end
def forgot_password(user)
+ visit root_path
click_on 'Forgot your password?'
fill_in 'Email', with: user.email
click_button 'Reset password'
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index b0259026630..d97831aae14 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -8,14 +8,14 @@ describe "Runners" do
describe "specific runners" do
before do
- @project = FactoryGirl.create :ci_project
- @project.gl_project.team << [user, :master]
+ @project = FactoryGirl.create :empty_project, shared_runners_enabled: false
+ @project.team << [user, :master]
- @project2 = FactoryGirl.create :ci_project
- @project2.gl_project.team << [user, :master]
+ @project2 = FactoryGirl.create :empty_project
+ @project2.team << [user, :master]
- @project3 = FactoryGirl.create :ci_project
- @project3.gl_project.team << [user, :developer]
+ @project3 = FactoryGirl.create :empty_project
+ @project3.team << [user, :developer]
@shared_runner = FactoryGirl.create :ci_shared_runner
@specific_runner = FactoryGirl.create :ci_specific_runner
@@ -25,7 +25,7 @@ describe "Runners" do
@project2.runners << @specific_runner2
@project3.runners << @specific_runner3
- visit runners_path(@project.gl_project)
+ visit runners_path(@project)
end
before do
@@ -49,7 +49,7 @@ describe "Runners" do
it "disables specific runner for project" do
@project2.runners << @specific_runner
- visit runners_path(@project.gl_project)
+ visit runners_path(@project)
within ".activated-specific-runners" do
click_on "Disable for this project"
@@ -69,9 +69,9 @@ describe "Runners" do
describe "shared runners" do
before do
- @project = FactoryGirl.create :ci_project
- @project.gl_project.team << [user, :master]
- visit runners_path(@project.gl_project)
+ @project = FactoryGirl.create :empty_project, shared_runners_enabled: false
+ @project.team << [user, :master]
+ visit runners_path(@project)
end
it "enables shared runners" do
@@ -82,14 +82,14 @@ describe "Runners" do
describe "show page" do
before do
- @project = FactoryGirl.create :ci_project
- @project.gl_project.team << [user, :master]
+ @project = FactoryGirl.create :empty_project
+ @project.team << [user, :master]
@specific_runner = FactoryGirl.create :ci_specific_runner
@project.runners << @specific_runner
end
it "shows runner information" do
- visit runners_path(@project.gl_project)
+ visit runners_path(@project)
click_on @specific_runner.short_sha
expect(page).to have_content(@specific_runner.platform)
end
diff --git a/spec/features/security/group_access_spec.rb b/spec/features/security/group_access_spec.rb
index 4b78e3a61f0..65f8073c693 100644
--- a/spec/features/security/group_access_spec.rb
+++ b/spec/features/security/group_access_spec.rb
@@ -16,11 +16,11 @@ describe 'Group access', feature: true do
end
end
- def group_member(access_level, group = group)
+ def group_member(access_level, grp = group())
level = Object.const_get("Gitlab::Access::#{access_level.upcase}")
create(:user).tap do |user|
- group.add_user(user, level)
+ grp.add_user(user, level)
end
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index fca3c77fc64..b7368cca29d 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -47,7 +47,7 @@ feature 'Task Lists', feature: true do
it 'contains the required selectors' do
visit_issue(project, issue)
- container = '.issue-details .description.js-task-list-container'
+ container = '.detail-page-description .description.js-task-list-container'
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
@@ -123,7 +123,7 @@ feature 'Task Lists', feature: true do
it 'contains the required selectors' do
visit_merge_request(project, merge)
- container = '.merge-request-details .description.js-task-list-container'
+ container = '.detail-page-description .description.js-task-list-container'
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 69492d58878..3cbc8253ad6 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -5,10 +5,9 @@ describe 'Triggers' do
before { login_as(user) }
before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
- visit namespace_project_triggers_path(@gl_project.namespace, @gl_project)
+ @project = FactoryGirl.create :empty_project
+ @project.team << [user, :master]
+ visit namespace_project_triggers_path(@project.namespace, @project)
end
context 'create a trigger' do
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index adb602f3edd..afea1840cd7 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -6,13 +6,12 @@ describe "Variables" do
describe "specific runners" do
before do
- @project = FactoryGirl.create :ci_project
- @gl_project = @project.gl_project
- @gl_project.team << [user, :master]
+ @project = FactoryGirl.create :empty_project
+ @project.team << [user, :master]
end
it "creates variable", js: true do
- visit namespace_project_variables_path(@gl_project.namespace, @gl_project)
+ visit namespace_project_variables_path(@project.namespace, @project)
click_on "Add a variable"
fill_in "Key", with: "SECRET_KEY"
fill_in "Value", with: "SECRET_VALUE"
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index d1dede78f74..f32641ef0f6 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -3,10 +3,19 @@ require 'spec_helper'
describe ProjectsFinder do
describe '#execute' do
let(:user) { create(:user) }
+ let(:group) { create(:group) }
- let!(:private_project) { create(:project, :private) }
- let!(:internal_project) { create(:project, :internal) }
- let!(:public_project) { create(:project, :public) }
+ let!(:private_project) do
+ create(:project, :private, name: 'A', path: 'A')
+ end
+
+ let!(:internal_project) do
+ create(:project, :internal, group: group, name: 'B', path: 'B')
+ end
+
+ let!(:public_project) do
+ create(:project, :public, group: group, name: 'C', path: 'C')
+ end
let(:finder) { described_class.new }
@@ -38,8 +47,6 @@ describe ProjectsFinder do
end
describe 'with a group' do
- let(:group) { public_project.group }
-
describe 'without a user' do
subject { finder.execute(nil, group: group) }
diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb
index 41d12afa9ce..e8dfc5c0eb1 100644
--- a/spec/fixtures/markdown.md.erb
+++ b/spec/fixtures/markdown.md.erb
@@ -153,6 +153,7 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Ignores invalid: <%= User.reference_prefix %>fake_user
- Ignored in code: `<%= user.to_reference %>`
- Ignored in links: [Link to <%= user.to_reference %>](#user-link)
+- Link to user by reference: [User](<%= user.to_reference %>)
#### IssueReferenceFilter
@@ -160,6 +161,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Issue in another project: <%= xissue.to_reference(project) %>
- Ignored in code: `<%= issue.to_reference %>`
- Ignored in links: [Link to <%= issue.to_reference %>](#issue-link)
+- Issue by URL: <%= urls.namespace_project_issue_url(issue.project.namespace, issue.project, issue) %>
+- Link to issue by reference: [Issue](<%= issue.to_reference %>)
+- Link to issue by URL: [Issue](<%= urls.namespace_project_issue_url(issue.project.namespace, issue.project, issue) %>)
#### MergeRequestReferenceFilter
@@ -167,6 +171,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Merge request in another project: <%= xmerge_request.to_reference(project) %>
- Ignored in code: `<%= merge_request.to_reference %>`
- Ignored in links: [Link to <%= merge_request.to_reference %>](#merge-request-link)
+- Merge request by URL: <%= urls.namespace_project_merge_request_url(merge_request.project.namespace, merge_request.project, merge_request) %>
+- Link to merge request by reference: [Merge request](<%= merge_request.to_reference %>)
+- Link to merge request by URL: [Merge request](<%= urls.namespace_project_merge_request_url(merge_request.project.namespace, merge_request.project, merge_request) %>)
#### SnippetReferenceFilter
@@ -174,6 +181,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Snippet in another project: <%= xsnippet.to_reference(project) %>
- Ignored in code: `<%= snippet.to_reference %>`
- Ignored in links: [Link to <%= snippet.to_reference %>](#snippet-link)
+- Snippet by URL: <%= urls.namespace_project_snippet_url(snippet.project.namespace, snippet.project, snippet) %>
+- Link to snippet by reference: [Snippet](<%= snippet.to_reference %>)
+- Link to snippet by URL: [Snippet](<%= urls.namespace_project_snippet_url(snippet.project.namespace, snippet.project, snippet) %>)
#### CommitRangeReferenceFilter
@@ -181,6 +191,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Range in another project: <%= xcommit_range.to_reference(project) %>
- Ignored in code: `<%= commit_range.to_reference %>`
- Ignored in links: [Link to <%= commit_range.to_reference %>](#commit-range-link)
+- Range by URL: <%= urls.namespace_project_compare_url(commit_range.project.namespace, commit_range.project, commit_range.to_param) %>
+- Link to range by reference: [Range](<%= commit_range.to_reference %>)
+- Link to range by URL: [Range](<%= urls.namespace_project_compare_url(commit_range.project.namespace, commit_range.project, commit_range.to_param) %>)
#### CommitReferenceFilter
@@ -188,6 +201,9 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Commit in another project: <%= xcommit.to_reference(project) %>
- Ignored in code: `<%= commit.to_reference %>`
- Ignored in links: [Link to <%= commit.to_reference %>](#commit-link)
+- Commit by URL: <%= urls.namespace_project_commit_url(commit.project.namespace, commit.project, commit) %>
+- Link to commit by reference: [Commit](<%= commit.to_reference %>)
+- Link to commit by URL: [Commit](<%= urls.namespace_project_commit_url(commit.project.namespace, commit.project, commit) %>)
#### LabelReferenceFilter
@@ -196,6 +212,7 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- Label by name in quotes: <%= label.to_reference(:name) %>
- Ignored in code: `<%= simple_label.to_reference %>`
- Ignored in links: [Link to <%= simple_label.to_reference %>](#label-link)
+- Link to label by reference: [Label](<%= label.to_reference %>)
### Task Lists
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 1dfae0fbd3f..68527c3a4f8 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -59,7 +59,7 @@ describe ApplicationHelper do
avatar_url = "http://localhost/uploads/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).
- to eq "<img alt=\"Banana sample\" src=\"#{avatar_url}\" />"
+ to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />"
end
it 'should give uploaded icon when present' do
@@ -95,9 +95,9 @@ describe ApplicationHelper do
end
it 'should call gravatar_icon when no User exists with the given email' do
- expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20)
+ expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20, 2)
- helper.avatar_icon('foo@example.com', 20)
+ helper.avatar_icon('foo@example.com', 20, 2)
end
describe 'using a User' do
@@ -150,15 +150,19 @@ describe ApplicationHelper do
stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}')
expect(gravatar_icon(user_email, 20)).
- to eq('http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118')
+ to eq('http://example.local/?s=40&hash=b58c6f14d292556214bd64909bcdb118')
end
it 'accepts a custom size argument' do
- expect(helper.gravatar_icon(user_email, 64)).to include '?s=64'
+ expect(helper.gravatar_icon(user_email, 64)).to include '?s=128'
end
- it 'defaults size to 40 when given an invalid size' do
- expect(helper.gravatar_icon(user_email, nil)).to include '?s=40'
+ it 'defaults size to 40@2x when given an invalid size' do
+ expect(helper.gravatar_icon(user_email, nil)).to include '?s=80'
+ end
+
+ it 'accepts a scaling factor' do
+ expect(helper.gravatar_icon(user_email, 40, 3)).to include '?s=120'
end
it 'ignores case and surrounding whitespace' do
@@ -259,11 +263,12 @@ describe ApplicationHelper do
end
it 'includes a default js-timeago class' do
- expect(element.attr('class')).to eq 'time_ago js-timeago'
+ expect(element.attr('class')).to eq 'time_ago js-timeago js-timeago-pending'
end
it 'accepts a custom html_class' do
- expect(element(html_class: 'custom_class').attr('class')).to eq 'custom_class js-timeago'
+ expect(element(html_class: 'custom_class').attr('class')).
+ to eq 'custom_class js-timeago js-timeago-pending'
end
it 'accepts a custom tooltip placement' do
@@ -274,7 +279,7 @@ describe ApplicationHelper do
el = element.next_element
expect(el.name).to eq 'script'
- expect(el.text).to include "$('.js-timeago').timeago()"
+ expect(el.text).to include "$('.js-timeago-pending').removeClass('js-timeago-pending').timeago()"
end
it 'allows the script tag to be excluded' do
diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb
index 7fc53eb1472..4f8d9c67262 100644
--- a/spec/helpers/ci_status_helper_spec.rb
+++ b/spec/helpers/ci_status_helper_spec.rb
@@ -6,13 +6,8 @@ describe CiStatusHelper do
let(:success_commit) { double("Ci::Commit", status: 'success') }
let(:failed_commit) { double("Ci::Commit", status: 'failed') }
- describe 'ci_status_color' do
- it { expect(ci_status_icon(success_commit)).to include('fa-check') }
- it { expect(ci_status_icon(failed_commit)).to include('fa-close') }
- end
-
- describe 'ci_status_color' do
- it { expect(ci_status_color(success_commit)).to eq('green') }
- it { expect(ci_status_color(failed_commit)).to eq('red') }
+ describe 'ci_status_icon' do
+ it { expect(helper.ci_status_icon(success_commit)).to include('fa-check') }
+ it { expect(helper.ci_status_icon(failed_commit)).to include('fa-close') }
end
end
diff --git a/spec/helpers/groups_helper.rb b/spec/helpers/groups_helper.rb
index 5d174460681..4ea90a80a92 100644
--- a/spec/helpers/groups_helper.rb
+++ b/spec/helpers/groups_helper.rb
@@ -9,7 +9,7 @@ describe GroupsHelper do
group.avatar = File.open(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/group/avatar/#{group.id}/banana_sample.gif")
end
it 'should give default avatar_icon when no avatar is present' do
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
index c4f7693329c..aafc24397a9 100644
--- a/spec/helpers/visibility_level_helper_spec.rb
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -7,69 +7,52 @@ describe VisibilityLevelHelper do
init_haml_helpers
end
- let(:project) { create(:project) }
+ let(:project) { build(:project) }
+ let(:personal_snippet) { build(:personal_snippet) }
+ let(:project_snippet) { build(:project_snippet) }
describe 'visibility_level_description' do
- shared_examples 'a visibility level description' do
- let(:desc) do
- visibility_level_description(Gitlab::VisibilityLevel::PRIVATE,
- form_model)
- end
-
- let(:expected_class) do
- class_name = case form_model.class.name
- when 'String'
- form_model
- else
- form_model.class.name
- end
-
- class_name.match(/(project|snippet)$/i)[0]
- end
-
- it 'should refer to the correct class' do
- expect(desc).to match(/#{expected_class}/i)
+ context 'used with a Project' do
+ it 'delegates projects to #project_visibility_level_description' do
+ expect(visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, project))
+ .to match /project/i
end
end
- context 'form_model argument is a String' do
- context 'model object is a personal snippet' do
- it_behaves_like 'a visibility level description' do
- let(:form_model) { 'PersonalSnippet' }
- end
+ context 'called with a Snippet' do
+ it 'delegates snippets to #snippet_visibility_level_description' do
+ expect(visibility_level_description(Gitlab::VisibilityLevel::INTERNAL, project_snippet))
+ .to match /snippet/i
end
+ end
+ end
- context 'model object is a project snippet' do
- it_behaves_like 'a visibility level description' do
- let(:form_model) { 'ProjectSnippet' }
- end
- end
+ describe "#project_visibility_level_description" do
+ it "describes private projects" do
+ expect(project_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE))
+ .to eq "Project access must be granted explicitly to each user."
+ end
- context 'model object is a project' do
- it_behaves_like 'a visibility level description' do
- let(:form_model) { 'Project' }
- end
- end
+ it "describes public projects" do
+ expect(project_visibility_level_description(Gitlab::VisibilityLevel::PUBLIC))
+ .to eq "The project can be cloned without any authentication."
end
+ end
- context 'form_model argument is a model object' do
- context 'model object is a personal snippet' do
- it_behaves_like 'a visibility level description' do
- let(:form_model) { create(:personal_snippet) }
- end
- end
+ describe "#snippet_visibility_level_description" do
+ it 'describes visibility only for me' do
+ expect(snippet_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, personal_snippet))
+ .to eq "The snippet is visible only to me."
+ end
- context 'model object is a project snippet' do
- it_behaves_like 'a visibility level description' do
- let(:form_model) { create(:project_snippet, project: project) }
- end
- end
+ it 'describes visibility for project members' do
+ expect(snippet_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, project_snippet))
+ .to eq "The snippet is visible only to project members."
+ end
- context 'model object is a project' do
- it_behaves_like 'a visibility level description' do
- let(:form_model) { project }
- end
- end
+ it 'defaults to personal snippet' do
+ expect(snippet_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE))
+ .to eq "The snippet is visible only to me."
end
end
diff --git a/spec/javascripts/fixtures/issues_show.html.haml b/spec/javascripts/fixtures/issues_show.html.haml
index 7e8b2a64351..8447dfdda32 100644
--- a/spec/javascripts/fixtures/issues_show.html.haml
+++ b/spec/javascripts/fixtures/issues_show.html.haml
@@ -1,6 +1,6 @@
%a.btn-close
-.issue-details
+.detail-page-description
.description.js-task-list-container
.wiki
%ul.task-list
diff --git a/spec/javascripts/fixtures/merge_request_tabs.html.haml b/spec/javascripts/fixtures/merge_request_tabs.html.haml
index 7624a713948..68678c3d7e3 100644
--- a/spec/javascripts/fixtures/merge_request_tabs.html.haml
+++ b/spec/javascripts/fixtures/merge_request_tabs.html.haml
@@ -1,12 +1,12 @@
%ul.nav.nav-tabs.merge-request-tabs
%li.notes-tab
- %a{href: '/foo/bar/merge_requests/1', data: {target: '#notes', action: 'notes', toggle: 'tab'}}
+ %a{href: '/foo/bar/merge_requests/1', data: {target: 'div#notes', action: 'notes', toggle: 'tab'}}
Discussion
%li.commits-tab
- %a{href: '/foo/bar/merge_requests/1/commits', data: {target: '#commits', action: 'commits', toggle: 'tab'}}
+ %a{href: '/foo/bar/merge_requests/1/commits', data: {target: 'div#commits', action: 'commits', toggle: 'tab'}}
Commits
%li.diffs-tab
- %a{href: '/foo/bar/merge_requests/1/diffs', data: {target: '#diffs', action: 'diffs', toggle: 'tab'}}
+ %a{href: '/foo/bar/merge_requests/1/diffs', data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'}}
Diffs
.tab-content
diff --git a/spec/javascripts/fixtures/merge_requests_show.html.haml b/spec/javascripts/fixtures/merge_requests_show.html.haml
index f0c622935f8..8447dfdda32 100644
--- a/spec/javascripts/fixtures/merge_requests_show.html.haml
+++ b/spec/javascripts/fixtures/merge_requests_show.html.haml
@@ -1,6 +1,6 @@
%a.btn-close
-.merge-request-details
+.detail-page-description
.description.js-task-list-container
.wiki
%ul.task-list
diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
new file mode 100644
index 00000000000..81b9a513ce3
--- /dev/null
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Banzai::CrossProjectReference, lib: true do
+ include described_class
+
+ describe '#project_from_ref' do
+ context 'when no project was referenced' do
+ it 'returns the project from context' do
+ project = double
+
+ allow(self).to receive(:context).and_return({ project: project })
+
+ expect(project_from_ref(nil)).to eq project
+ end
+ end
+
+ context 'when referenced project does not exist' do
+ it 'returns nil' do
+ expect(project_from_ref('invalid/reference')).to be_nil
+ end
+ end
+
+ context 'when referenced project exists' do
+ it 'returns the referenced project' do
+ project2 = double('referenced project')
+
+ expect(Project).to receive(:find_with_namespace).
+ with('cross/reference').and_return(project2)
+
+ expect(project_from_ref('cross/reference')).to eq project2
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
new file mode 100644
index 00000000000..84c2ddf444e
--- /dev/null
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -0,0 +1,112 @@
+require 'spec_helper'
+
+describe Banzai::Filter::AutolinkFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:link) { 'http://about.gitlab.com/' }
+
+ it 'does nothing when :autolink is false' do
+ exp = act = link
+ expect(filter(act, autolink: false).to_html).to eq exp
+ end
+
+ it 'does nothing with non-link text' do
+ exp = act = 'This text contains no links to autolink'
+ expect(filter(act).to_html).to eq exp
+ end
+
+ context 'Rinku schemes' do
+ it 'autolinks http' do
+ doc = filter("See #{link}")
+ expect(doc.at_css('a').text).to eq link
+ expect(doc.at_css('a')['href']).to eq link
+ end
+
+ it 'autolinks https' do
+ link = 'https://google.com/'
+ doc = filter("See #{link}")
+
+ expect(doc.at_css('a').text).to eq link
+ expect(doc.at_css('a')['href']).to eq link
+ end
+
+ it 'autolinks ftp' do
+ link = 'ftp://ftp.us.debian.org/debian/'
+ doc = filter("See #{link}")
+
+ expect(doc.at_css('a').text).to eq link
+ expect(doc.at_css('a')['href']).to eq link
+ end
+
+ it 'autolinks short URLs' do
+ link = 'http://localhost:3000/'
+ doc = filter("See #{link}")
+
+ expect(doc.at_css('a').text).to eq link
+ expect(doc.at_css('a')['href']).to eq link
+ end
+
+ it 'accepts link_attr options' do
+ doc = filter("See #{link}", link_attr: { class: 'custom' })
+
+ expect(doc.at_css('a')['class']).to eq 'custom'
+ end
+
+ described_class::IGNORE_PARENTS.each do |elem|
+ it "ignores valid links contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>See #{link}</#{elem}>"
+ expect(filter(act).to_html).to eq exp
+ end
+ end
+ end
+
+ context 'other schemes' do
+ let(:link) { 'foo://bar.baz/' }
+
+ it 'autolinks smb' do
+ link = 'smb:///Volumes/shared/foo.pdf'
+ doc = filter("See #{link}")
+
+ expect(doc.at_css('a').text).to eq link
+ expect(doc.at_css('a')['href']).to eq link
+ end
+
+ it 'autolinks irc' do
+ link = 'irc://irc.freenode.net/git'
+ doc = filter("See #{link}")
+
+ expect(doc.at_css('a').text).to eq link
+ expect(doc.at_css('a')['href']).to eq link
+ end
+
+ it 'does not include trailing punctuation' do
+ doc = filter("See #{link}.")
+ expect(doc.at_css('a').text).to eq link
+
+ doc = filter("See #{link}, ok?")
+ expect(doc.at_css('a').text).to eq link
+
+ doc = filter("See #{link}...")
+ expect(doc.at_css('a').text).to eq link
+ end
+
+ it 'does not include trailing HTML entities' do
+ doc = filter("See &lt;&lt;&lt;#{link}&gt;&gt;&gt;")
+
+ expect(doc.at_css('a')['href']).to eq link
+ expect(doc.text).to eq "See <<<#{link}>>>"
+ end
+
+ it 'accepts link_attr options' do
+ doc = filter("See #{link}", link_attr: { class: 'custom' })
+ expect(doc.at_css('a')['class']).to eq 'custom'
+ end
+
+ described_class::IGNORE_PARENTS.each do |elem|
+ it "ignores valid links contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>See #{link}</#{elem}>"
+ expect(filter(act).to_html).to eq exp
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
new file mode 100644
index 00000000000..c2a8ad36c30
--- /dev/null
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -0,0 +1,182 @@
+require 'spec_helper'
+
+describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:project) { create(:project, :public) }
+ let(:commit1) { project.commit("HEAD~2") }
+ let(:commit2) { project.commit }
+
+ let(:range) { CommitRange.new("#{commit1.id}...#{commit2.id}", project) }
+ let(:range2) { CommitRange.new("#{commit1.id}..#{commit2.id}", project) }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Commit Range #{range.to_reference}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'internal reference' do
+ let(:reference) { range.to_reference }
+ let(:reference2) { range2.to_reference }
+
+ it 'links to a valid two-dot reference' do
+ doc = reference_filter("See #{reference2}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_compare_url(project.namespace, project, range2.to_param)
+ end
+
+ it 'links to a valid three-dot reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_compare_url(project.namespace, project, range.to_param)
+ end
+
+ it 'links to a valid short ID' do
+ reference = "#{commit1.short_id}...#{commit2.id}"
+ reference2 = "#{commit1.id}...#{commit2.short_id}"
+
+ exp = commit1.short_id + '...' + commit2.short_id
+
+ expect(reference_filter("See #{reference}").css('a').first.text).to eq exp
+ expect(reference_filter("See #{reference2}").css('a').first.text).to eq exp
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ exp = Regexp.escape(range.reference_link_text)
+ expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid commit IDs' do
+ exp = act = "See #{commit1.id.reverse}...#{commit2.id}"
+
+ expect(project).to receive(:valid_repo?).and_return(true)
+ expect(project.repository).to receive(:commit).with(commit1.id.reverse)
+ expect(project.repository).to receive(:commit).with(commit2.id)
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'includes a title attribute' do
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.attr('title')).to eq range.reference_title
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit_range'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-commit-range attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-commit-range')
+ expect(link.attr('data-commit-range')).to eq range.to_s
+ end
+
+ it 'supports an :only_path option' do
+ doc = reference_filter("See #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.namespace_project_compare_url(project.namespace, project, from: commit1.id, to: commit2.id, only_path: true)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit_range]).not_to be_empty
+ end
+ end
+
+ context 'cross-project reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:reference) { range.to_reference(project) }
+
+ before do
+ range.project = project2
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ exp = Regexp.escape("#{project2.to_reference}@#{range.reference_link_text}")
+ expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
+ expect(reference_filter(act).to_html).to eq exp
+
+ exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit_range]).not_to be_empty
+ end
+ end
+
+ context 'cross-project URL reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:range) { CommitRange.new("#{commit1.id}...master", project) }
+ let(:reference) { urls.namespace_project_compare_url(project2.namespace, project2, from: commit1.id, to: 'master') }
+
+ before do
+ range.project = project2
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq reference
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ exp = Regexp.escape(range.reference_link_text(project))
+ expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
+ expect(reference_filter(act).to_html).to eq exp
+
+ exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit_range]).not_to be_empty
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
new file mode 100644
index 00000000000..473534ba68a
--- /dev/null
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -0,0 +1,163 @@
+require 'spec_helper'
+
+describe Banzai::Filter::CommitReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:project) { create(:project, :public) }
+ let(:commit) { project.commit }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Commit #{commit.id}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'internal reference' do
+ let(:reference) { commit.id }
+
+ # Let's test a variety of commit SHA sizes just to be paranoid
+ [6, 8, 12, 18, 20, 32, 40].each do |size|
+ it "links to a valid reference of #{size} characters" do
+ doc = reference_filter("See #{reference[0...size]}")
+
+ expect(doc.css('a').first.text).to eq commit.short_id
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_commit_url(project.namespace, project, reference)
+ end
+ end
+
+ it 'always uses the short ID as the link text' do
+ doc = reference_filter("See #{commit.id}")
+ expect(doc.text).to eq "See #{commit.short_id}"
+
+ doc = reference_filter("See #{commit.id[0...6]}")
+ expect(doc.text).to eq "See #{commit.short_id}"
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("See (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{commit.short_id}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid commit IDs' do
+ invalid = invalidate_reference(reference)
+ exp = act = "See #{invalid}"
+
+ expect(project).to receive(:valid_repo?).and_return(true)
+ expect(project.repository).to receive(:commit).with(invalid)
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'includes a title attribute' do
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.attr('title')).to eq commit.link_title
+ end
+
+ it 'escapes the title attribute' do
+ allow_any_instance_of(Commit).to receive(:title).and_return(%{"></a>whatever<a title="})
+
+ doc = reference_filter("See #{reference}")
+ expect(doc.text).to eq "See #{commit.short_id}"
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-commit attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-commit')
+ expect(link.attr('data-commit')).to eq commit.id
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("See #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.namespace_project_commit_url(project.namespace, project, reference, only_path: true)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit]).not_to be_empty
+ end
+ end
+
+ context 'cross-project reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:commit) { project2.commit }
+ let(:reference) { commit.to_reference(project) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ exp = Regexp.escape(project2.to_reference)
+ expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Committed #{invalidate_reference(reference)}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit]).not_to be_empty
+ end
+ end
+
+ context 'cross-project URL reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:commit) { project2.commit }
+ let(:reference) { urls.namespace_project_commit_url(project2.namespace, project2, commit.id) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.to_html).to match(/\(<a.+>#{commit.reference_link_text(project)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ act = "Committed #{invalidate_reference(reference)}"
+ expect(reference_filter(act).to_html).to match(/<a.+>#{Regexp.escape(invalidate_reference(reference))}<\/a>/)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit]).not_to be_empty
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb
new file mode 100644
index 00000000000..cf314058158
--- /dev/null
+++ b/spec/lib/banzai/filter/emoji_filter_spec.rb
@@ -0,0 +1,98 @@
+require 'spec_helper'
+
+describe Banzai::Filter::EmojiFilter, lib: true do
+ include FilterSpecHelper
+
+ before do
+ @original_asset_host = ActionController::Base.asset_host
+ ActionController::Base.asset_host = 'https://foo.com'
+ end
+
+ after do
+ ActionController::Base.asset_host = @original_asset_host
+ end
+
+ it 'replaces supported emoji' do
+ doc = filter('<p>:heart:</p>')
+ expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/emoji/2764.png'
+ end
+
+ it 'ignores unsupported emoji' do
+ exp = act = '<p>:foo:</p>'
+ doc = filter(act)
+ expect(doc.to_html).to match Regexp.escape(exp)
+ end
+
+ it 'correctly encodes the URL' do
+ doc = filter('<p>:+1:</p>')
+ expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/emoji/1F44D.png'
+ end
+
+ it 'matches at the start of a string' do
+ doc = filter(':+1:')
+ expect(doc.css('img').size).to eq 1
+ end
+
+ it 'matches at the end of a string' do
+ doc = filter('This gets a :-1:')
+ expect(doc.css('img').size).to eq 1
+ end
+
+ it 'matches with adjacent text' do
+ doc = filter('+1 (:+1:)')
+ expect(doc.css('img').size).to eq 1
+ end
+
+ it 'matches multiple emoji in a row' do
+ doc = filter(':see_no_evil::hear_no_evil::speak_no_evil:')
+ expect(doc.css('img').size).to eq 3
+ end
+
+ it 'has a title attribute' do
+ doc = filter(':-1:')
+ expect(doc.css('img').first.attr('title')).to eq ':-1:'
+ end
+
+ it 'has an alt attribute' do
+ doc = filter(':-1:')
+ expect(doc.css('img').first.attr('alt')).to eq ':-1:'
+ end
+
+ it 'has an align attribute' do
+ doc = filter(':8ball:')
+ expect(doc.css('img').first.attr('align')).to eq 'absmiddle'
+ end
+
+ it 'has an emoji class' do
+ doc = filter(':cat:')
+ expect(doc.css('img').first.attr('class')).to eq 'emoji'
+ end
+
+ it 'has height and width attributes' do
+ doc = filter(':dog:')
+ img = doc.css('img').first
+
+ expect(img.attr('width')).to eq '20'
+ expect(img.attr('height')).to eq '20'
+ end
+
+ it 'keeps whitespace intact' do
+ doc = filter('This deserves a :+1:, big time.')
+
+ expect(doc.to_html).to match(/^This deserves a <img.+>, big time\.\z/)
+ end
+
+ it 'uses a custom asset_root context' do
+ root = Gitlab.config.gitlab.url + 'gitlab/root'
+
+ doc = filter(':smile:', asset_root: root)
+ expect(doc.css('img').first.attr('src')).to start_with(root)
+ end
+
+ it 'uses a custom asset_host context' do
+ ActionController::Base.asset_host = 'https://cdn.example.com'
+
+ doc = filter(':frowning:', asset_host: 'https://this-is-ignored-i-guess?')
+ expect(doc.css('img').first.attr('src')).to start_with('https://cdn.example.com')
+ end
+end
diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
new file mode 100644
index 00000000000..953466679e4
--- /dev/null
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -0,0 +1,77 @@
+require 'spec_helper'
+
+describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ def helper
+ IssuesHelper
+ end
+
+ let(:project) { create(:jira_project) }
+
+ context 'JIRA issue references' do
+ let(:issue) { ExternalIssue.new('JIRA-123', project) }
+ let(:reference) { issue.to_reference }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Issue #{reference}</#{elem}>"
+ expect(filter(act).to_html).to eq exp
+ end
+ end
+
+ it 'ignores valid references when using default tracker' do
+ expect(project).to receive(:default_issues_tracker?).and_return(true)
+
+ exp = act = "Issue #{reference}"
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'links to a valid reference' do
+ doc = filter("Issue #{reference}")
+ expect(doc.css('a').first.attr('href'))
+ .to eq helper.url_for_issue(reference, project)
+ end
+
+ it 'links to the external tracker' do
+ doc = filter("Issue #{reference}")
+ link = doc.css('a').first.attr('href')
+
+ expect(link).to eq "http://jira.example/browse/#{reference}"
+ end
+
+ it 'links with adjacent text' do
+ doc = filter("Issue (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
+ end
+
+ it 'includes a title attribute' do
+ doc = filter("Issue #{reference}")
+ expect(doc.css('a').first.attr('title')).to eq "Issue in JIRA tracker"
+ end
+
+ it 'escapes the title attribute' do
+ allow(project.external_issue_tracker).to receive(:title).
+ and_return(%{"></a>whatever<a title="})
+
+ doc = filter("Issue #{reference}")
+ expect(doc.text).to eq "Issue #{reference}"
+ end
+
+ it 'includes default classes' do
+ doc = filter("Issue #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
+ end
+
+ it 'supports an :only_path context' do
+ doc = filter("Issue #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).to eq helper.url_for_issue("#{reference}", project, only_path: true)
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
new file mode 100644
index 00000000000..e3a8e15330e
--- /dev/null
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe Banzai::Filter::ExternalLinkFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'ignores elements without an href attribute' do
+ exp = act = %q(<a id="ignored">Ignore Me</a>)
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'ignores non-HTTP(S) links' do
+ exp = act = %q(<a href="irc://irc.freenode.net/gitlab">IRC</a>)
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'skips internal links' do
+ internal = Gitlab.config.gitlab.url
+ exp = act = %Q(<a href="#{internal}/sign_in">Login</a>)
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'adds rel="nofollow" to external links' do
+ act = %q(<a href="https://google.com/">Google</a>)
+ doc = filter(act)
+
+ expect(doc.at_css('a')).to have_attribute('rel')
+ expect(doc.at_css('a')['rel']).to eq 'nofollow'
+ end
+end
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
new file mode 100644
index 00000000000..5a0d3d577a8
--- /dev/null
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -0,0 +1,209 @@
+require 'spec_helper'
+
+describe Banzai::Filter::IssueReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ def helper
+ IssuesHelper
+ end
+
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, project: project) }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Issue #{issue.to_reference}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'internal reference' do
+ let(:reference) { issue.to_reference }
+
+ it 'ignores valid references when using non-default tracker' do
+ expect(project).to receive(:get_issue).with(issue.iid).and_return(nil)
+
+ exp = act = "Issue #{reference}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter("Fixed #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid issue IDs' do
+ invalid = invalidate_reference(reference)
+ exp = act = "Fixed #{invalid}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'includes a title attribute' do
+ doc = reference_filter("Issue #{reference}")
+ expect(doc.css('a').first.attr('title')).to eq "Issue: #{issue.title}"
+ end
+
+ it 'escapes the title attribute' do
+ issue.update_attribute(:title, %{"></a>whatever<a title="})
+
+ doc = reference_filter("Issue #{reference}")
+ expect(doc.text).to eq "Issue #{reference}"
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("Issue #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Issue #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-issue attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-issue')
+ expect(link.attr('data-issue')).to eq issue.id.to_s
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Issue #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq helper.url_for_issue(issue.iid, project, only_path: true)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
+ end
+
+ context 'cross-project reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:issue) { create(:issue, project: project2) }
+ let(:reference) { issue.to_reference(project) }
+
+ it 'ignores valid references when cross-reference project uses external tracker' do
+ expect_any_instance_of(Project).to receive(:get_issue).
+ with(issue.iid).and_return(nil)
+
+ exp = act = "Issue #{reference}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project2)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid issue IDs on the referenced project' do
+ exp = act = "Fixed #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
+ end
+
+ context 'cross-project URL reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:issue) { create(:issue, project: project2) }
+ let(:reference) { helper.url_for_issue(issue.iid, project2) + "#note_123" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq reference
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(issue.to_reference(project))} \(comment 123\)<\/a>\.\)/)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
+ end
+
+ context 'cross-project reference in link href' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:issue) { create(:issue, project: project2) }
+ let(:reference) { %Q{<a href="#{issue.to_reference(project)}">Reference</a>} }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project2)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
+ end
+
+ context 'cross-project URL in link href' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:issue) { create(:issue, project: project2) }
+ let(:reference) { %Q{<a href="#{helper.url_for_issue(issue.iid, project2) + "#note_123"}">Reference</a>} }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project2) + "#note_123"
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
new file mode 100644
index 00000000000..b46ccc47605
--- /dev/null
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -0,0 +1,179 @@
+require 'spec_helper'
+require 'html/pipeline'
+
+describe Banzai::Filter::LabelReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:project) { create(:empty_project, :public) }
+ let(:label) { create(:label, project: project) }
+ let(:reference) { label.to_reference }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Label #{reference}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("Label #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Label #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-label attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-label')
+ expect(link.attr('data-label')).to eq label.id.to_s
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Label #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.namespace_project_issues_path(project.namespace, project, label_name: label.name)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Label #{reference}")
+ expect(result[:references][:label]).to eq [label]
+ end
+
+ describe 'label span element' do
+ it 'includes default classes' do
+ doc = reference_filter("Label #{reference}")
+ expect(doc.css('a span').first.attr('class')).to eq 'label color-label'
+ end
+
+ it 'includes a style attribute' do
+ doc = reference_filter("Label #{reference}")
+ expect(doc.css('a span').first.attr('style')).to match(/\Abackground-color: #\h{6}; color: #\h{6}\z/)
+ end
+ end
+
+ context 'Integer-based references' do
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Label (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
+ end
+
+ it 'ignores invalid label IDs' do
+ exp = act = "Label #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'String-based single-word references' do
+ let(:label) { create(:label, name: 'gfm', project: project) }
+ let(:reference) { "#{Label.reference_prefix}#{label.name}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ expect(doc.text).to eq 'See gfm'
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Label (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
+ end
+
+ it 'ignores invalid label names' do
+ exp = act = "Label #{Label.reference_prefix}#{label.name.reverse}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'String-based multi-word references in quotes' do
+ let(:label) { create(:label, name: 'gfm references', project: project) }
+ let(:reference) { label.to_reference(:name) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ expect(doc.text).to eq 'See gfm references'
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Label (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
+ end
+
+ it 'ignores invalid label names' do
+ exp = act = %(Label #{Label.reference_prefix}"#{label.name.reverse}")
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'edge cases' do
+ it 'gracefully handles non-references matching the pattern' do
+ exp = act = '(format nil "~0f" 3.0) ; 3.0'
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'referencing a label in a link href' do
+ let(:reference) { %Q{<a href="#{label.to_reference}">Label</a>} }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_issues_url(project.namespace, project, label_name: label.name)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Label (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>Label</a>\.\)))
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Label #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-label attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-label')
+ expect(link.attr('data-label')).to eq label.id.to_s
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Label #{reference}")
+ expect(result[:references][:label]).to eq [label]
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
new file mode 100644
index 00000000000..352710df307
--- /dev/null
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -0,0 +1,142 @@
+require 'spec_helper'
+
+describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:project) { create(:project, :public) }
+ let(:merge) { create(:merge_request, source_project: project) }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Merge #{merge.to_reference}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'internal reference' do
+ let(:reference) { merge.to_reference }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_merge_request_url(project.namespace, project, merge)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Merge (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid merge IDs' do
+ exp = act = "Merge #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'includes a title attribute' do
+ doc = reference_filter("Merge #{reference}")
+ expect(doc.css('a').first.attr('title')).to eq "Merge Request: #{merge.title}"
+ end
+
+ it 'escapes the title attribute' do
+ merge.update_attribute(:title, %{"></a>whatever<a title="})
+
+ doc = reference_filter("Merge #{reference}")
+ expect(doc.text).to eq "Merge #{reference}"
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("Merge #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Merge #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-merge-request attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-merge-request')
+ expect(link.attr('data-merge-request')).to eq merge.id.to_s
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Merge #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.namespace_project_merge_request_url(project.namespace, project, merge, only_path: true)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Merge #{reference}")
+ expect(result[:references][:merge_request]).to eq [merge]
+ end
+ end
+
+ context 'cross-project reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:merge) { create(:merge_request, source_project: project2) }
+ let(:reference) { merge.to_reference(project) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_merge_request_url(project2.namespace,
+ project, merge)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Merge (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid merge IDs on the referenced project' do
+ exp = act = "Merge #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Merge #{reference}")
+ expect(result[:references][:merge_request]).to eq [merge]
+ end
+ end
+
+ context 'cross-project URL reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:merge) { create(:merge_request, source_project: project2, target_project: project2) }
+ let(:reference) { urls.namespace_project_merge_request_url(project2.namespace, project2, merge) + '/diffs#note_123' }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq reference
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Merge (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(merge.to_reference(project))} \(diffs, comment 123\)<\/a>\.\)/)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Merge #{reference}")
+ expect(result[:references][:merge_request]).to eq [merge]
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
new file mode 100644
index 00000000000..e9bb388e361
--- /dev/null
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+describe Banzai::Filter::RedactorFilter, lib: true do
+ include ActionView::Helpers::UrlHelper
+ include FilterSpecHelper
+
+ it 'ignores non-GFM links' do
+ html = %(See <a href="https://google.com/">Google</a>)
+ doc = filter(html, current_user: double)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ def reference_link(data)
+ link_to('text', '', class: 'gfm', data: data)
+ end
+
+ context 'with data-project' do
+ it 'removes unpermitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+
+ link = reference_link(project: project.id, reference_filter: 'ReferenceFilter')
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 0
+ end
+
+ it 'allows permitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+ project.team << [user, :master]
+
+ link = reference_link(project: project.id, reference_filter: 'ReferenceFilter')
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'handles invalid Project references' do
+ link = reference_link(project: 12345, reference_filter: 'ReferenceFilter')
+
+ expect { filter(link) }.not_to raise_error
+ end
+ end
+
+ context "for user references" do
+
+ context 'with data-group' do
+ it 'removes unpermitted Group references' do
+ user = create(:user)
+ group = create(:group)
+
+ link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 0
+ end
+
+ it 'allows permitted Group references' do
+ user = create(:user)
+ group = create(:group)
+ group.add_developer(user)
+
+ link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'handles invalid Group references' do
+ link = reference_link(group: 12345, reference_filter: 'UserReferenceFilter')
+
+ expect { filter(link) }.not_to raise_error
+ end
+ end
+
+ context 'with data-user' do
+ it 'allows any User reference' do
+ user = create(:user)
+
+ link = reference_link(user: user.id, reference_filter: 'UserReferenceFilter')
+ doc = filter(link)
+
+ expect(doc.css('a').length).to eq 1
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb b/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb
new file mode 100644
index 00000000000..c8b1dfdf944
--- /dev/null
+++ b/spec/lib/banzai/filter/reference_gatherer_filter_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+describe Banzai::Filter::ReferenceGathererFilter, lib: true do
+ include ActionView::Helpers::UrlHelper
+ include FilterSpecHelper
+
+ def reference_link(data)
+ link_to('text', '', class: 'gfm', data: data)
+ end
+
+ context "for issue references" do
+
+ context 'with data-project' do
+ it 'removes unpermitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+ issue = create(:issue, project: project)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:issue]).to be_empty
+ end
+
+ it 'allows permitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+ issue = create(:issue, project: project)
+ project.team << [user, :master]
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: 'IssueReferenceFilter')
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:issue]).to eq([issue])
+ end
+
+ it 'handles invalid Project references' do
+ link = reference_link(project: 12345, issue: 12345, reference_filter: 'IssueReferenceFilter')
+
+ expect { pipeline_result(link) }.not_to raise_error
+ end
+ end
+ end
+
+ context "for user references" do
+
+ context 'with data-group' do
+ it 'removes unpermitted Group references' do
+ user = create(:user)
+ group = create(:group)
+
+ link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:user]).to be_empty
+ end
+
+ it 'allows permitted Group references' do
+ user = create(:user)
+ group = create(:group)
+ group.add_developer(user)
+
+ link = reference_link(group: group.id, reference_filter: 'UserReferenceFilter')
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:user]).to eq([user])
+ end
+
+ it 'handles invalid Group references' do
+ link = reference_link(group: 12345, reference_filter: 'UserReferenceFilter')
+
+ expect { pipeline_result(link) }.not_to raise_error
+ end
+ end
+
+ context 'with data-user' do
+ it 'allows any User reference' do
+ user = create(:user)
+
+ link = reference_link(user: user.id, reference_filter: 'UserReferenceFilter')
+ result = pipeline_result(link)
+
+ expect(result[:references][:user]).to eq([user])
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
new file mode 100644
index 00000000000..0b3e5ecbc9f
--- /dev/null
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -0,0 +1,147 @@
+# encoding: UTF-8
+
+require 'spec_helper'
+
+describe Banzai::Filter::RelativeLinkFilter, lib: true do
+ def filter(doc, contexts = {})
+ contexts.reverse_merge!({
+ commit: project.commit,
+ project: project,
+ project_wiki: project_wiki,
+ ref: ref,
+ requested_path: requested_path
+ })
+
+ described_class.call(doc, contexts)
+ end
+
+ def image(path)
+ %(<img src="#{path}" />)
+ end
+
+ def link(path)
+ %(<a href="#{path}">#{path}</a>)
+ end
+
+ let(:project) { create(:project) }
+ let(:project_path) { project.path_with_namespace }
+ let(:ref) { 'markdown' }
+ let(:project_wiki) { nil }
+ let(:requested_path) { '/' }
+
+ shared_examples :preserve_unchanged do
+ it 'does not modify any relative URL in anchor' do
+ doc = filter(link('README.md'))
+ expect(doc.at_css('a')['href']).to eq 'README.md'
+ end
+
+ it 'does not modify any relative URL in image' do
+ doc = filter(image('files/images/logo-black.png'))
+ expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
+ end
+ end
+
+ shared_examples :relative_to_requested do
+ it 'rebuilds URL relative to the requested path' do
+ doc = filter(link('users.md'))
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/blob/#{ref}/doc/api/users.md"
+ end
+ end
+
+ context 'with a project_wiki' do
+ let(:project_wiki) { double('ProjectWiki') }
+ include_examples :preserve_unchanged
+ end
+
+ context 'without a repository' do
+ let(:project) { create(:empty_project) }
+ include_examples :preserve_unchanged
+ end
+
+ context 'with an empty repository' do
+ let(:project) { create(:project_empty_repo) }
+ include_examples :preserve_unchanged
+ end
+
+ it 'does not raise an exception on invalid URIs' do
+ act = link("://foo")
+ expect { filter(act) }.not_to raise_error
+ end
+
+ context 'with a valid repository' do
+ it 'rebuilds relative URL for a file in the repo' do
+ doc = filter(link('doc/api/README.md'))
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
+ end
+
+ it 'rebuilds relative URL for a file in the repo up one directory' do
+ relative_link = link('../api/README.md')
+ doc = filter(relative_link, requested_path: 'doc/update/7.14-to-8.0.md')
+
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
+ end
+
+ it 'rebuilds relative URL for a file in the repo up multiple directories' do
+ relative_link = link('../../../api/README.md')
+ doc = filter(relative_link, requested_path: 'doc/foo/bar/baz/README.md')
+
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
+ end
+
+ it 'rebuilds relative URL for a file in the repo with an anchor' do
+ doc = filter(link('README.md#section'))
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/blob/#{ref}/README.md#section"
+ end
+
+ it 'rebuilds relative URL for a directory in the repo' do
+ doc = filter(link('doc/api/'))
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/tree/#{ref}/doc/api"
+ end
+
+ it 'rebuilds relative URL for an image in the repo' do
+ doc = filter(link('files/images/logo-black.png'))
+ expect(doc.at_css('a')['href']).
+ to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png"
+ end
+
+ it 'does not modify relative URL with an anchor only' do
+ doc = filter(link('#section-1'))
+ expect(doc.at_css('a')['href']).to eq '#section-1'
+ end
+
+ it 'does not modify absolute URL' do
+ doc = filter(link('http://example.com'))
+ expect(doc.at_css('a')['href']).to eq 'http://example.com'
+ end
+
+ it 'supports Unicode filenames' do
+ path = 'files/images/한글.png'
+ escaped = Addressable::URI.escape(path)
+
+ # Stub these methods so the file doesn't actually need to be in the repo
+ allow_any_instance_of(described_class).
+ to receive(:file_exists?).and_return(true)
+ allow_any_instance_of(described_class).
+ to receive(:image?).with(path).and_return(true)
+
+ doc = filter(image(escaped))
+ expect(doc.at_css('img')['src']).to match '/raw/'
+ end
+
+ context 'when requested path is a file in the repo' do
+ let(:requested_path) { 'doc/api/README.md' }
+ include_examples :relative_to_requested
+ end
+
+ context 'when requested path is a directory in the repo' do
+ let(:requested_path) { 'doc/api' }
+ include_examples :relative_to_requested
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
new file mode 100644
index 00000000000..760d60a4190
--- /dev/null
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -0,0 +1,197 @@
+require 'spec_helper'
+
+describe Banzai::Filter::SanitizationFilter, lib: true do
+ include FilterSpecHelper
+
+ describe 'default whitelist' do
+ it 'sanitizes tags that are not whitelisted' do
+ act = %q{<textarea>no inputs</textarea> and <blink>no blinks</blink>}
+ exp = 'no inputs and no blinks'
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'sanitizes tag attributes' do
+ act = %q{<a href="http://example.com/bar.html" onclick="bar">Text</a>}
+ exp = %q{<a href="http://example.com/bar.html">Text</a>}
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'sanitizes javascript in attributes' do
+ act = %q(<a href="javascript:alert('foo')">Text</a>)
+ exp = '<a>Text</a>'
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'allows whitelisted HTML tags from the user' do
+ exp = act = "<dl>\n<dt>Term</dt>\n<dd>Definition</dd>\n</dl>"
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'sanitizes `class` attribute on any element' do
+ act = %q{<strong class="foo">Strong</strong>}
+ expect(filter(act).to_html).to eq %q{<strong>Strong</strong>}
+ end
+
+ it 'sanitizes `id` attribute on any element' do
+ act = %q{<em id="foo">Emphasis</em>}
+ expect(filter(act).to_html).to eq %q{<em>Emphasis</em>}
+ end
+ end
+
+ describe 'custom whitelist' do
+ it 'customizes the whitelist only once' do
+ instance = described_class.new('Foo')
+ 3.times { instance.whitelist }
+
+ expect(instance.whitelist[:transformers].size).to eq 5
+ end
+
+ it 'allows syntax highlighting' do
+ exp = act = %q{<pre class="code highlight white c"><code><span class="k">def</span></code></pre>}
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'sanitizes `class` attribute from non-highlight spans' do
+ act = %q{<span class="k">def</span>}
+ expect(filter(act).to_html).to eq %q{<span>def</span>}
+ end
+
+ it 'allows `style` attribute on table elements' do
+ html = <<-HTML.strip_heredoc
+ <table>
+ <tr><th style="text-align: center">Head</th></tr>
+ <tr><td style="text-align: right">Body</th></tr>
+ </table>
+ HTML
+
+ doc = filter(html)
+
+ expect(doc.at_css('th')['style']).to eq 'text-align: center'
+ expect(doc.at_css('td')['style']).to eq 'text-align: right'
+ end
+
+ it 'allows `span` elements' do
+ exp = act = %q{<span>Hello</span>}
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'removes `rel` attribute from `a` elements' do
+ act = %q{<a href="#" rel="nofollow">Link</a>}
+ exp = %q{<a href="#">Link</a>}
+
+ expect(filter(act).to_html).to eq exp
+ end
+
+ # Adapted from the Sanitize test suite: http://git.io/vczrM
+ protocols = {
+ 'protocol-based JS injection: simple, no spaces' => {
+ input: '<a href="javascript:alert(\'XSS\');">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: simple, spaces before' => {
+ input: '<a href="javascript :alert(\'XSS\');">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: simple, spaces after' => {
+ input: '<a href="javascript: alert(\'XSS\');">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: simple, spaces before and after' => {
+ input: '<a href="javascript : alert(\'XSS\');">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: preceding colon' => {
+ input: '<a href=":javascript:alert(\'XSS\');">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: UTF-8 encoding' => {
+ input: '<a href="javascript&#58;">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: long UTF-8 encoding' => {
+ input: '<a href="javascript&#0058;">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: long UTF-8 encoding without semicolons' => {
+ input: '<a href=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: hex encoding' => {
+ input: '<a href="javascript&#x3A;">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: long hex encoding' => {
+ input: '<a href="javascript&#x003A;">foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: hex encoding without semicolons' => {
+ input: '<a href=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>foo</a>',
+ output: '<a>foo</a>'
+ },
+
+ 'protocol-based JS injection: null char' => {
+ input: "<a href=java\0script:alert(\"XSS\")>foo</a>",
+ output: '<a href="java"></a>'
+ },
+
+ 'protocol-based JS injection: spaces and entities' => {
+ input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>',
+ output: '<a href="">foo</a>'
+ },
+ }
+
+ protocols.each do |name, data|
+ it "handles #{name}" do
+ doc = filter(data[:input])
+
+ expect(doc.to_html).to eq data[:output]
+ end
+ end
+
+ it 'allows non-standard anchor schemes' do
+ exp = %q{<a href="irc://irc.freenode.net/git">IRC</a>}
+ act = filter(exp)
+
+ expect(act.to_html).to eq exp
+ end
+
+ it 'allows relative links' do
+ exp = %q{<a href="foo/bar.md">foo/bar.md</a>}
+ act = filter(exp)
+
+ expect(act.to_html).to eq exp
+ end
+ end
+
+ context 'when inline_sanitization is true' do
+ it 'uses a stricter whitelist' do
+ doc = filter('<h1>Description</h1>', inline_sanitization: true)
+ expect(doc.to_html.strip).to eq 'Description'
+ end
+
+ %w(pre code img ol ul li).each do |elem|
+ it "removes '#{elem}' elements" do
+ act = "<#{elem}>Description</#{elem}>"
+ expect(filter(act, inline_sanitization: true).to_html.strip).
+ to eq 'Description'
+ end
+ end
+
+ %w(b i strong em a ins del sup sub p).each do |elem|
+ it "still allows '#{elem}' elements" do
+ exp = act = "<#{elem}>Description</#{elem}>"
+ expect(filter(act, inline_sanitization: true).to_html).to eq exp
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
new file mode 100644
index 00000000000..26466fbb180
--- /dev/null
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -0,0 +1,146 @@
+require 'spec_helper'
+
+describe Banzai::Filter::SnippetReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:project) { create(:empty_project, :public) }
+ let(:snippet) { create(:project_snippet, project: project) }
+ let(:reference) { snippet.to_reference }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Snippet #{reference}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'internal reference' do
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_snippet_url(project.namespace, project, snippet)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Snippet (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid snippet IDs' do
+ exp = act = "Snippet #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'includes a title attribute' do
+ doc = reference_filter("Snippet #{reference}")
+ expect(doc.css('a').first.attr('title')).to eq "Snippet: #{snippet.title}"
+ end
+
+ it 'escapes the title attribute' do
+ snippet.update_attribute(:title, %{"></a>whatever<a title="})
+
+ doc = reference_filter("Snippet #{reference}")
+ expect(doc.text).to eq "Snippet #{reference}"
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("Snippet #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-snippet'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Snippet #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-snippet attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-snippet')
+ expect(link.attr('data-snippet')).to eq snippet.id.to_s
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Snippet #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.namespace_project_snippet_url(project.namespace, project, snippet, only_path: true)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Snippet #{reference}")
+ expect(result[:references][:snippet]).to eq [snippet]
+ end
+ end
+
+ context 'cross-project reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:snippet) { create(:project_snippet, project: project2) }
+ let(:reference) { snippet.to_reference(project) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("See (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid snippet IDs on the referenced project' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Snippet #{reference}")
+ expect(result[:references][:snippet]).to eq [snippet]
+ end
+ end
+
+ context 'cross-project URL reference' do
+ let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:snippet) { create(:project_snippet, project: project2) }
+ let(:reference) { urls.namespace_project_snippet_url(project2.namespace, project2, snippet) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("See (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(snippet.to_reference(project))}<\/a>\.\)/)
+ end
+
+ it 'ignores invalid snippet IDs on the referenced project' do
+ act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to match(/<a.+>#{Regexp.escape(invalidate_reference(reference))}<\/a>/)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Snippet #{reference}")
+ expect(result[:references][:snippet]).to eq [snippet]
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
new file mode 100644
index 00000000000..407617f3307
--- /dev/null
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'highlights valid code blocks' do
+ result = filter('<pre><code>def fun end</code>')
+ expect(result.to_html).to eq("<pre class=\"code highlight js-syntax-highlight plaintext\"><code>def fun end</code></pre>\n")
+ end
+
+ it 'passes through invalid code blocks' do
+ allow_any_instance_of(described_class).to receive(:block_code).and_raise(StandardError)
+
+ result = filter('<pre><code>This is a test</code></pre>')
+ expect(result.to_html).to eq('<pre>This is a test</pre>')
+ end
+end
diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
new file mode 100644
index 00000000000..6a5d003e87f
--- /dev/null
+++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
@@ -0,0 +1,97 @@
+# encoding: UTF-8
+
+require 'spec_helper'
+
+describe Banzai::Filter::TableOfContentsFilter, lib: true do
+ include FilterSpecHelper
+
+ def header(level, text)
+ "<h#{level}>#{text}</h#{level}>\n"
+ end
+
+ it 'does nothing when :no_header_anchors is truthy' do
+ exp = act = header(1, 'Header')
+ expect(filter(act, no_header_anchors: 1).to_html).to eq exp
+ end
+
+ it 'does nothing with empty headers' do
+ exp = act = header(1, nil)
+ expect(filter(act).to_html).to eq exp
+ end
+
+ 1.upto(6) do |i|
+ it "processes h#{i} elements" do
+ html = header(i, "Header #{i}")
+ doc = filter(html)
+
+ expect(doc.css("h#{i} a").first.attr('id')).to eq "header-#{i}"
+ end
+ end
+
+ describe 'anchor tag' do
+ it 'has an `anchor` class' do
+ doc = filter(header(1, 'Header'))
+ expect(doc.css('h1 a').first.attr('class')).to eq 'anchor'
+ end
+
+ it 'links to the id' do
+ doc = filter(header(1, 'Header'))
+ expect(doc.css('h1 a').first.attr('href')).to eq '#header'
+ end
+
+ describe 'generated IDs' do
+ it 'translates spaces to dashes' do
+ doc = filter(header(1, 'This header has spaces in it'))
+ expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-has-spaces-in-it'
+ end
+
+ it 'squeezes multiple spaces and dashes' do
+ doc = filter(header(1, 'This---header is poorly-formatted'))
+ expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-is-poorly-formatted'
+ end
+
+ it 'removes punctuation' do
+ doc = filter(header(1, "This, header! is, filled. with @ punctuation?"))
+ expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-is-filled-with-punctuation'
+ end
+
+ it 'appends a unique number to duplicates' do
+ doc = filter(header(1, 'One') + header(2, 'One'))
+
+ expect(doc.css('h1 a').first.attr('id')).to eq 'one'
+ expect(doc.css('h2 a').first.attr('id')).to eq 'one-1'
+ end
+
+ it 'supports Unicode' do
+ doc = filter(header(1, '한글'))
+ expect(doc.css('h1 a').first.attr('id')).to eq '한글'
+ expect(doc.css('h1 a').first.attr('href')).to eq '#한글'
+ end
+ end
+ end
+
+ describe 'result' do
+ def result(html)
+ HTML::Pipeline.new([described_class]).call(html)
+ end
+
+ let(:results) { result(header(1, 'Header 1') + header(2, 'Header 2')) }
+ let(:doc) { Nokogiri::XML::DocumentFragment.parse(results[:toc]) }
+
+ it 'is contained within a `ul` element' do
+ expect(doc.children.first.name).to eq 'ul'
+ expect(doc.children.first.attr('class')).to eq 'section-nav'
+ end
+
+ it 'contains an `li` element for each header' do
+ expect(doc.css('li').length).to eq 2
+
+ links = doc.css('li a')
+
+ expect(links.first.attr('href')).to eq '#header-1'
+ expect(links.first.text).to eq 'Header 1'
+ expect(links.last.attr('href')).to eq '#header-2'
+ expect(links.last.text).to eq 'Header 2'
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/task_list_filter_spec.rb b/spec/lib/banzai/filter/task_list_filter_spec.rb
new file mode 100644
index 00000000000..f2e3a44478d
--- /dev/null
+++ b/spec/lib/banzai/filter/task_list_filter_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+
+describe Banzai::Filter::TaskListFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'does not apply `task-list` class to non-task lists' do
+ exp = act = %(<ul><li>Item</li></ul>)
+ expect(filter(act).to_html).to eq exp
+ end
+end
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
new file mode 100644
index 00000000000..3b073a90a95
--- /dev/null
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -0,0 +1,73 @@
+# encoding: UTF-8
+
+require 'spec_helper'
+
+describe Banzai::Filter::UploadLinkFilter, lib: true do
+ def filter(doc, contexts = {})
+ contexts.reverse_merge!({
+ project: project
+ })
+
+ described_class.call(doc, contexts)
+ end
+
+ def image(path)
+ %(<img src="#{path}" />)
+ end
+
+ def link(path)
+ %(<a href="#{path}">#{path}</a>)
+ end
+
+ let(:project) { create(:project) }
+
+ shared_examples :preserve_unchanged do
+ it 'does not modify any relative URL in anchor' do
+ doc = filter(link('README.md'))
+ expect(doc.at_css('a')['href']).to eq 'README.md'
+ end
+
+ it 'does not modify any relative URL in image' do
+ doc = filter(image('files/images/logo-black.png'))
+ expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
+ end
+ end
+
+ it 'does not raise an exception on invalid URIs' do
+ act = link("://foo")
+ expect { filter(act) }.not_to raise_error
+ end
+
+ context 'with a valid repository' do
+ it 'rebuilds relative URL for a link' do
+ doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('a')['href']).
+ to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ end
+
+ it 'rebuilds relative URL for an image' do
+ doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('a')['href']).
+ to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ end
+
+ it 'does not modify absolute URL' do
+ doc = filter(link('http://example.com'))
+ expect(doc.at_css('a')['href']).to eq 'http://example.com'
+ end
+
+ it 'supports Unicode filenames' do
+ path = '/uploads/한글.png'
+ escaped = Addressable::URI.escape(path)
+
+ # Stub these methods so the file doesn't actually need to be in the repo
+ allow_any_instance_of(described_class).
+ to receive(:file_exists?).and_return(true)
+ allow_any_instance_of(described_class).
+ to receive(:image?).with(path).and_return(true)
+
+ doc = filter(image(escaped))
+ expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
new file mode 100644
index 00000000000..3534bf97784
--- /dev/null
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -0,0 +1,147 @@
+require 'spec_helper'
+
+describe Banzai::Filter::UserReferenceFilter, lib: true do
+ include FilterSpecHelper
+
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:reference) { user.to_reference }
+
+ it 'requires project context' do
+ expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
+ end
+
+ it 'ignores invalid users' do
+ exp = act = "Hey #{invalidate_reference(reference)}"
+ expect(reference_filter(act).to_html).to eq(exp)
+ end
+
+ %w(pre code a style).each do |elem|
+ it "ignores valid references contained inside '#{elem}' element" do
+ exp = act = "<#{elem}>Hey #{reference}</#{elem}>"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'mentioning @all' do
+ let(:reference) { User.reference_prefix + 'all' }
+
+ before do
+ project.team << [project.creator, :developer]
+ end
+
+ it 'supports a special @all mention' do
+ doc = reference_filter("Hey #{reference}")
+ expect(doc.css('a').length).to eq 1
+ expect(doc.css('a').first.attr('href'))
+ .to eq urls.namespace_project_url(project.namespace, project)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Hey #{reference}")
+ expect(result[:references][:user]).to eq [project.creator]
+ end
+ end
+
+ context 'mentioning a user' do
+ it 'links to a User' do
+ doc = reference_filter("Hey #{reference}")
+ expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
+ end
+
+ it 'links to a User with a period' do
+ user = create(:user, name: 'alphA.Beta')
+
+ doc = reference_filter("Hey #{user.to_reference}")
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'links to a User with an underscore' do
+ user = create(:user, name: 'ping_pong_king')
+
+ doc = reference_filter("Hey #{user.to_reference}")
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'includes a data-user attribute' do
+ doc = reference_filter("Hey #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-user')
+ expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Hey #{reference}")
+ expect(result[:references][:user]).to eq [user]
+ end
+ end
+
+ context 'mentioning a group' do
+ let(:group) { create(:group) }
+ let(:reference) { group.to_reference }
+
+ it 'links to the Group' do
+ doc = reference_filter("Hey #{reference}")
+ expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
+ end
+
+ it 'includes a data-group attribute' do
+ doc = reference_filter("Hey #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-group')
+ expect(link.attr('data-group')).to eq group.id.to_s
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Hey #{reference}")
+ expect(result[:references][:user]).to eq group.users
+ end
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Mention me (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
+ end
+
+ it 'includes default classes' do
+ doc = reference_filter("Hey #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project_member'
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Hey #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.user_path(user)
+ end
+
+ context 'referencing a user in a link href' do
+ let(:reference) { %Q{<a href="#{user.to_reference}">User</a>} }
+
+ it 'links to a User' do
+ doc = reference_filter("Hey #{reference}")
+ expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Mention me (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>User<\/a>\.\)/)
+ end
+
+ it 'includes a data-user attribute' do
+ doc = reference_filter("Hey #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-user')
+ expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Hey #{reference}")
+ expect(result[:references][:user]).to eq [user]
+ end
+ end
+end
diff --git a/spec/lib/ci/ansi2html_spec.rb b/spec/lib/ci/ansi2html_spec.rb
index 75c023bbc43..3a2b568f4c7 100644
--- a/spec/lib/ci/ansi2html_spec.rb
+++ b/spec/lib/ci/ansi2html_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::Ansi2html do
+describe Ci::Ansi2html, lib: true do
subject { Ci::Ansi2html }
it "prints non-ansi as-is" do
diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb
index 83e2ad220b8..50a77308cde 100644
--- a/spec/lib/ci/charts_spec.rb
+++ b/spec/lib/ci/charts_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Charts" do
+describe Ci::Charts, lib: true do
context "build_times" do
before do
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index 6f287719ba6..c90133fbf03 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
module Ci
- describe GitlabCiYamlProcessor do
+ describe GitlabCiYamlProcessor, lib: true do
let(:path) { 'path' }
describe "#builds_for_ref" do
@@ -532,21 +532,21 @@ module Ci
end
it "returns errors if job stage is not a string" do
- config = YAML.dump({ rspec: { script: "test", type: 1, allow_failure: "string" } })
+ config = YAML.dump({ rspec: { script: "test", type: 1 } })
expect do
GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
end
it "returns errors if job stage is not a pre-defined stage" do
- config = YAML.dump({ rspec: { script: "test", type: "acceptance", allow_failure: "string" } })
+ config = YAML.dump({ rspec: { script: "test", type: "acceptance" } })
expect do
GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
end
it "returns errors if job stage is not a defined stage" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", type: "acceptance", allow_failure: "string" } })
+ config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", type: "acceptance" } })
expect do
GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test")
diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb
index a9624e9a2b7..c2a7b20b84d 100644
--- a/spec/lib/disable_email_interceptor_spec.rb
+++ b/spec/lib/disable_email_interceptor_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DisableEmailInterceptor do
+describe DisableEmailInterceptor, lib: true do
before do
ActionMailer::Base.register_interceptor(DisableEmailInterceptor)
end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 48bc60eed16..f38fadda9ba 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ExtractsPath do
+describe ExtractsPath, lib: true do
include ExtractsPath
include RepoHelpers
include Gitlab::Application.routes.url_helpers
diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb
index 12ccc051c74..fda6f9a6c88 100644
--- a/spec/lib/file_size_validator_spec.rb
+++ b/spec/lib/file_size_validator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::FileSizeValidatorSpec' do
+describe FileSizeValidator, lib: true do
let(:validator) { FileSizeValidator.new(options) }
let(:attachment) { AttachmentUploader.new }
let(:note) { create(:note) }
diff --git a/spec/lib/git_ref_validator_spec.rb b/spec/lib/git_ref_validator_spec.rb
index 4633b6f3934..dc57e94f193 100644
--- a/spec/lib/git_ref_validator_spec.rb
+++ b/spec/lib/git_ref_validator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitRefValidator do
+describe Gitlab::GitRefValidator, lib: true do
it { expect(Gitlab::GitRefValidator.validate('feature/new')).to be_truthy }
it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy }
it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy }
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 03e36fd3552..6beb21c6d2b 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
require 'nokogiri'
module Gitlab
- describe Asciidoc do
+ describe Asciidoc, lib: true do
let(:input) { '<b>ascii</b>' }
let(:context) { {} }
@@ -50,9 +50,9 @@ module Gitlab
filtered_html = '<b>ASCII</b>'
allow(Asciidoctor).to receive(:convert).and_return(html)
- expect_any_instance_of(HTML::Pipeline).to receive(:call)
- .with(html, context)
- .and_return(output: Nokogiri::HTML.fragment(filtered_html))
+ expect(Banzai).to receive(:render)
+ .with(html, context.merge(pipeline: :asciidoc))
+ .and_return(filtered_html)
expect( render('foo', context) ).to eql filtered_html
end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 72806bebe1f..aad291c03cd 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Auth do
+describe Gitlab::Auth, lib: true do
let(:gl_auth) { Gitlab::Auth.new }
describe :find do
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
index dfa0e10318a..cd26dca0998 100644
--- a/spec/lib/gitlab/backend/grack_auth_spec.rb
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Grack::Auth do
+describe Grack::Auth, lib: true do
let(:user) { create(:user) }
let(:project) { create(:project) }
@@ -191,15 +191,10 @@ describe Grack::Auth do
context "when a gitlab ci token is provided" do
let(:token) { "123" }
- let(:gitlab_ci_project) { FactoryGirl.create :ci_project, token: token }
+ let(:project) { FactoryGirl.create :empty_project }
before do
- project.gitlab_ci_project = gitlab_ci_project
- project.save
-
- gitlab_ci_service = project.build_gitlab_ci_service
- gitlab_ci_service.active = true
- gitlab_ci_service.save
+ project.update_attributes(runners_token: token, builds_enabled: true)
env["HTTP_AUTHORIZATION"] = ActionController::HttpAuthentication::Basic.encode_credentials("gitlab-ci-token", token)
end
diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb
index b60e23454d6..fd869f48b5c 100644
--- a/spec/lib/gitlab/backend/shell_spec.rb
+++ b/spec/lib/gitlab/backend/shell_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Shell do
+describe Gitlab::Shell, lib: true do
let(:project) { double('Project', id: 7, path: 'diaspora') }
let(:gitlab_shell) { Gitlab::Shell.new }
@@ -16,7 +16,7 @@ describe Gitlab::Shell do
it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") }
- describe Gitlab::Shell::KeyAdder do
+ describe Gitlab::Shell::KeyAdder, lib: true do
describe '#add_key' do
it 'normalizes space characters in the key' do
io = spy
diff --git a/spec/lib/gitlab/bitbucket_import/client_spec.rb b/spec/lib/gitlab/bitbucket_import/client_spec.rb
index dfe58637eee..aa0699f2ebf 100644
--- a/spec/lib/gitlab/bitbucket_import/client_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/client_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::Client do
+describe Gitlab::BitbucketImport::Client, lib: true do
let(:token) { '123456' }
let(:secret) { 'secret' }
let(:client) { Gitlab::BitbucketImport::Client.new(token, secret) }
diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
index 0e826a319e0..e1c60e07b4d 100644
--- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::BitbucketImport::ProjectCreator do
+describe Gitlab::BitbucketImport::ProjectCreator, lib: true do
let(:user) { create(:user) }
let(:repo) do
{
diff --git a/spec/lib/gitlab/build_data_builder_spec.rb b/spec/lib/gitlab/build_data_builder_spec.rb
new file mode 100644
index 00000000000..839b30f1ff4
--- /dev/null
+++ b/spec/lib/gitlab/build_data_builder_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe 'Gitlab::BuildDataBuilder' do
+ let(:build) { create(:ci_build) }
+
+ describe :build do
+ let(:data) do
+ Gitlab::BuildDataBuilder.build(build)
+ end
+
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:ref]).to eq(build.ref) }
+ it { expect(data[:sha]).to eq(build.sha) }
+ it { expect(data[:tag]).to eq(build.tag) }
+ it { expect(data[:build_id]).to eq(build.id) }
+ it { expect(data[:build_status]).to eq(build.status) }
+ it { expect(data[:project_id]).to eq(build.project.id) }
+ it { expect(data[:project_name]).to eq(build.project.name_with_namespace) }
+ end
+end
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 21254f778d3..99288da1e43 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -1,12 +1,19 @@
require 'spec_helper'
-describe Gitlab::ClosingIssueExtractor do
+describe Gitlab::ClosingIssueExtractor, lib: true do
let(:project) { create(:project) }
+ let(:project2) { create(:project) }
let(:issue) { create(:issue, project: project) }
+ let(:issue2) { create(:issue, project: project2) }
let(:reference) { issue.to_reference }
+ let(:cross_reference) { issue2.to_reference(project) }
subject { described_class.new(project, project.creator) }
+ before do
+ project2.team << [project.creator, :master]
+ end
+
describe "#closed_by_message" do
context 'with a single reference' do
it do
@@ -130,6 +137,27 @@ describe Gitlab::ClosingIssueExtractor do
end
end
+ context "with a cross-project reference" do
+ it do
+ message = "Closes #{cross_reference}"
+ expect(subject.closed_by_message(message)).to eq([issue2])
+ end
+ end
+
+ context "with a cross-project URL" do
+ it do
+ message = "Closes #{urls.namespace_project_issue_url(issue2.project.namespace, issue2.project, issue2)}"
+ expect(subject.closed_by_message(message)).to eq([issue2])
+ end
+ end
+
+ context "with an invalid URL" do
+ it do
+ message = "Closes https://google.com#{urls.namespace_project_issue_path(issue2.project.namespace, issue2.project, issue2)}"
+ expect(subject.closed_by_message(message)).to eq([])
+ end
+ end
+
context 'with multiple references' do
let(:other_issue) { create(:issue, project: project) }
let(:third_issue) { create(:issue, project: project) }
@@ -171,6 +199,31 @@ describe Gitlab::ClosingIssueExtractor do
expect(subject.closed_by_message(message)).
to match_array([issue, other_issue, third_issue])
end
+
+ it "fetches cross-project references" do
+ message = "Closes #{reference} and #{cross_reference}"
+
+ expect(subject.closed_by_message(message)).
+ to match_array([issue, issue2])
+ end
+
+ it "fetches cross-project URL references" do
+ message = "Closes #{urls.namespace_project_issue_url(issue2.project.namespace, issue2.project, issue2)} and #{reference}"
+
+ expect(subject.closed_by_message(message)).
+ to match_array([issue, issue2])
+ end
+
+ it "ignores invalid cross-project URL references" do
+ message = "Closes https://google.com#{urls.namespace_project_issue_path(issue2.project.namespace, issue2.project, issue2)} and #{reference}"
+
+ expect(subject.closed_by_message(message)).
+ to match_array([issue])
+ end
end
end
+
+ def urls
+ Gitlab::Application.routes.url_helpers
+ end
end
diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb
index c7be45dbcd3..0a1ec66f199 100644
--- a/spec/lib/gitlab/color_schemes_spec.rb
+++ b/spec/lib/gitlab/color_schemes_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ColorSchemes do
+describe Gitlab::ColorSchemes, lib: true do
describe '.body_classes' do
it 'returns a space-separated list of class names' do
css = described_class.body_classes
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 7cdebdf209a..8461e8ce50d 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Database do
+describe Gitlab::Database, lib: true do
# These are just simple smoke tests to check if the methods work (regardless
# of what they may return).
describe '.mysql?' do
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 8b7946f3117..c7cdf8691d6 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::File do
+describe Gitlab::Diff::File, lib: true do
include RepoHelpers
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb
index 4d5d1431683..ba577bd28e5 100644
--- a/spec/lib/gitlab/diff/parser_spec.rb
+++ b/spec/lib/gitlab/diff/parser_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Diff::Parser do
+describe Gitlab::Diff::Parser, lib: true do
include RepoHelpers
let(:project) { create(:project) }
diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb
index 8fb432367b6..476a21bf996 100644
--- a/spec/lib/gitlab/email/attachment_uploader_spec.rb
+++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::Email::AttachmentUploader do
+describe Gitlab::Email::AttachmentUploader, lib: true do
describe "#execute" do
let(:project) { build(:project) }
let(:message_raw) { fixture_file("emails/attachment.eml") }
diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb
new file mode 100644
index 00000000000..56ae2a8d121
--- /dev/null
+++ b/spec/lib/gitlab/email/message/repository_push_spec.rb
@@ -0,0 +1,122 @@
+require 'spec_helper'
+
+describe Gitlab::Email::Message::RepositoryPush do
+ include RepoHelpers
+
+ let!(:group) { create(:group, name: 'my_group') }
+ let!(:project) { create(:project, name: 'my_project', namespace: group) }
+ let!(:author) { create(:author, name: 'Author') }
+
+ let(:message) do
+ described_class.new(Notify, project.id, 'recipient@example.com', opts)
+ end
+
+ context 'new commits have been pushed to repository' do
+ let(:opts) do
+ { author_id: author.id, ref: 'master', action: :push, compare: compare,
+ send_from_committer_email: true }
+ end
+ let(:compare) do
+ Gitlab::Git::Compare.new(project.repository.raw_repository,
+ sample_image_commit.id, sample_commit.id)
+ end
+
+ describe '#project' do
+ subject { message.project }
+ it { is_expected.to eq project }
+ it { is_expected.to be_an_instance_of Project }
+ end
+
+ describe '#project_namespace' do
+ subject { message.project_namespace }
+ it { is_expected.to eq group }
+ it { is_expected.to be_kind_of Namespace }
+ end
+
+ describe '#project_name_with_namespace' do
+ subject { message.project_name_with_namespace }
+ it { is_expected.to eq 'my_group / my_project' }
+ end
+
+ describe '#author' do
+ subject { message.author }
+ it { is_expected.to eq author }
+ it { is_expected.to be_an_instance_of User }
+ end
+
+ describe '#author_name' do
+ subject { message.author_name }
+ it { is_expected.to eq 'Author' }
+ end
+
+ describe '#commits' do
+ subject { message.commits }
+ it { is_expected.to be_kind_of Array }
+ it { is_expected.to all(be_instance_of Commit) }
+ end
+
+ describe '#diffs' do
+ subject { message.diffs }
+ it { is_expected.to all(be_an_instance_of Gitlab::Git::Diff) }
+ end
+
+ describe '#diffs_count' do
+ subject { message.diffs_count }
+ it { is_expected.to eq compare.diffs.count }
+ end
+
+ describe '#compare' do
+ subject { message.compare }
+ it { is_expected.to be_an_instance_of Gitlab::Git::Compare }
+ end
+
+ describe '#compare_timeout' do
+ subject { message.compare_timeout }
+ it { is_expected.to eq compare.timeout }
+ end
+
+ describe '#reverse_compare?' do
+ subject { message.reverse_compare? }
+ it { is_expected.to eq false }
+ end
+
+ describe '#disable_diffs?' do
+ subject { message.disable_diffs? }
+ it { is_expected.to eq false }
+ end
+
+ describe '#send_from_committer_email?' do
+ subject { message.send_from_committer_email? }
+ it { is_expected.to eq true }
+ end
+
+ describe '#action_name' do
+ subject { message.action_name }
+ it { is_expected.to eq 'pushed to' }
+ end
+
+ describe '#ref_name' do
+ subject { message.ref_name }
+ it { is_expected.to eq 'master' }
+ end
+
+ describe '#ref_type' do
+ subject { message.ref_type }
+ it { is_expected.to eq 'branch' }
+ end
+
+ describe '#target_url' do
+ subject { message.target_url }
+ it { is_expected.to include 'compare' }
+ it { is_expected.to include compare.commits.first.parents.first.id }
+ it { is_expected.to include compare.commits.last.id }
+ end
+
+ describe '#subject' do
+ subject { message.subject }
+ it { is_expected.to include "[Git][#{project.path_with_namespace}]" }
+ it { is_expected.to include "#{compare.commits.length} commits" }
+ it { is_expected.to include compare.commits.first.message.split("\n").first }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb
index e470b7cd5f5..b535413bbd4 100644
--- a/spec/lib/gitlab/email/receiver_spec.rb
+++ b/spec/lib/gitlab/email/receiver_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::Email::Receiver do
+describe Gitlab::Email::Receiver, lib: true do
before do
stub_incoming_email_setting(enabled: true, address: "reply+%{key}@appmail.adventuretime.ooo")
end
diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb
index 7cae1da8050..6f8e9a4be64 100644
--- a/spec/lib/gitlab/email/reply_parser_spec.rb
+++ b/spec/lib/gitlab/email/reply_parser_spec.rb
@@ -1,7 +1,7 @@
require "spec_helper"
# Inspired in great part by Discourse's Email::Receiver
-describe Gitlab::Email::ReplyParser do
+describe Gitlab::Email::ReplyParser, lib: true do
describe '#execute' do
def test_parse_body(mail_string)
described_class.new(Mail::Message.new(mail_string)).execute
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index c7291689e32..9b3a0e3a75f 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitAccess do
+describe Gitlab::GitAccess, lib: true do
let(:access) { Gitlab::GitAccess.new(actor, project) }
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 4cb91094cb3..77ecfce6f17 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitAccessWiki do
+describe Gitlab::GitAccessWiki, lib: true do
let(:access) { Gitlab::GitAccessWiki.new(user, project) }
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb
index 26618120316..49d8cdf4314 100644
--- a/spec/lib/gitlab/github_import/client_spec.rb
+++ b/spec/lib/gitlab/github_import/client_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::Client do
+describe Gitlab::GithubImport::Client, lib: true do
let(:token) { '123456' }
let(:client) { Gitlab::GithubImport::Client.new(token) }
diff --git a/spec/lib/gitlab/github_import/project_creator_spec.rb b/spec/lib/gitlab/github_import/project_creator_spec.rb
index ca61d3c5234..c93a3ebdaec 100644
--- a/spec/lib/gitlab/github_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/github_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GithubImport::ProjectCreator do
+describe Gitlab::GithubImport::ProjectCreator, lib: true do
let(:user) { create(:user) }
let(:repo) do
OpenStruct.new(
diff --git a/spec/lib/gitlab/gitlab_import/client_spec.rb b/spec/lib/gitlab/gitlab_import/client_spec.rb
index c511c515474..e6831e7c383 100644
--- a/spec/lib/gitlab/gitlab_import/client_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/client_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitlabImport::Client do
+describe Gitlab::GitlabImport::Client, lib: true do
let(:token) { '123456' }
let(:client) { Gitlab::GitlabImport::Client.new(token) }
diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
index 2d8923d14bb..483f65cd053 100644
--- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitlabImport::ProjectCreator do
+describe Gitlab::GitlabImport::ProjectCreator, lib: true do
let(:user) { create(:user) }
let(:repo) do
{
diff --git a/spec/lib/gitlab/gitorious_import/project_creator_spec.rb b/spec/lib/gitlab/gitorious_import/project_creator_spec.rb
index c1125ca6357..946712ca38e 100644
--- a/spec/lib/gitlab/gitorious_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/gitorious_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GitoriousImport::ProjectCreator do
+describe Gitlab::GitoriousImport::ProjectCreator, lib: true do
let(:user) { create(:user) }
let(:repo) { Gitlab::GitoriousImport::Repository.new('foo/bar-baz-qux') }
let(:namespace){ create(:group, owner: user) }
diff --git a/spec/lib/gitlab/google_code_import/client_spec.rb b/spec/lib/gitlab/google_code_import/client_spec.rb
index 37985c062b4..85949ae8dc4 100644
--- a/spec/lib/gitlab/google_code_import/client_spec.rb
+++ b/spec/lib/gitlab/google_code_import/client_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::GoogleCodeImport::Client do
+describe Gitlab::GoogleCodeImport::Client, lib: true do
let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) }
subject { described_class.new(raw_data) }
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 65ad7524cc2..647631271e0 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::GoogleCodeImport::Importer do
+describe Gitlab::GoogleCodeImport::Importer, lib: true do
let(:mapped_user) { create(:user, username: "thilo123") }
let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) }
let(:client) { Gitlab::GoogleCodeImport::Client.new(raw_data) }
diff --git a/spec/lib/gitlab/google_code_import/project_creator_spec.rb b/spec/lib/gitlab/google_code_import/project_creator_spec.rb
index 35549b48687..499a896ee76 100644
--- a/spec/lib/gitlab/google_code_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/google_code_import/project_creator_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GoogleCodeImport::ProjectCreator do
+describe Gitlab::GoogleCodeImport::ProjectCreator, lib: true do
let(:user) { create(:user) }
let(:repo) do
Gitlab::GoogleCodeImport::Repository.new(
diff --git a/spec/lib/gitlab/incoming_email_spec.rb b/spec/lib/gitlab/incoming_email_spec.rb
index 5fdb9c723b1..bcdba8d4c12 100644
--- a/spec/lib/gitlab/incoming_email_spec.rb
+++ b/spec/lib/gitlab/incoming_email_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::IncomingEmail do
+describe Gitlab::IncomingEmail, lib: true do
describe "self.enabled?" do
context "when reply by email is enabled" do
before do
diff --git a/spec/lib/gitlab/inline_diff_spec.rb b/spec/lib/gitlab/inline_diff_spec.rb
index 2e0a05088cc..c690c195112 100644
--- a/spec/lib/gitlab/inline_diff_spec.rb
+++ b/spec/lib/gitlab/inline_diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::InlineDiff do
+describe Gitlab::InlineDiff, lib: true do
describe '#processing' do
let(:diff) do
<<eos
diff --git a/spec/lib/gitlab/key_fingerprint_spec.rb b/spec/lib/gitlab/key_fingerprint_spec.rb
index 266eab6e793..d09f51f3bfc 100644
--- a/spec/lib/gitlab/key_fingerprint_spec.rb
+++ b/spec/lib/gitlab/key_fingerprint_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe Gitlab::KeyFingerprint do
+describe Gitlab::KeyFingerprint, lib: true do
let(:key) { "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" }
let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" }
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index c38f212b405..a628d0c0157 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::Access do
+describe Gitlab::LDAP::Access, lib: true do
let(:access) { Gitlab::LDAP::Access.new user }
let(:user) { create(:omniauth_user) }
@@ -13,6 +13,11 @@ describe Gitlab::LDAP::Access do
end
it { is_expected.to be_falsey }
+
+ it 'should block user in GitLab' do
+ access.allowed?
+ expect(user).to be_blocked
+ end
end
context 'when the user is found' do
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index 38076602df9..4847b5f3b0e 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::Adapter do
+describe Gitlab::LDAP::Adapter, lib: true do
let(:adapter) { Gitlab::LDAP::Adapter.new 'ldapmain' }
describe '#dn_matches_filter?' do
diff --git a/spec/lib/gitlab/ldap/auth_hash_spec.rb b/spec/lib/gitlab/ldap/auth_hash_spec.rb
index 7d8268536a4..6a53ed1db64 100644
--- a/spec/lib/gitlab/ldap/auth_hash_spec.rb
+++ b/spec/lib/gitlab/ldap/auth_hash_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::AuthHash do
+describe Gitlab::LDAP::AuthHash, lib: true do
let(:auth_hash) do
Gitlab::LDAP::AuthHash.new(
OmniAuth::AuthHash.new(
diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb
index 6e3de914a45..b8f3290e84c 100644
--- a/spec/lib/gitlab/ldap/authentication_spec.rb
+++ b/spec/lib/gitlab/ldap/authentication_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::Authentication do
+describe Gitlab::LDAP::Authentication, lib: true do
let(:user) { create(:omniauth_user, extern_uid: dn) }
let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
let(:login) { 'john' }
diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb
index 3548d647c84..835853a83a4 100644
--- a/spec/lib/gitlab/ldap/config_spec.rb
+++ b/spec/lib/gitlab/ldap/config_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::Config do
+describe Gitlab::LDAP::Config, lib: true do
let(:config) { Gitlab::LDAP::Config.new provider }
let(:provider) { 'ldapmain' }
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index b5b56a34952..3bba5e2efa2 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::LDAP::User do
+describe Gitlab::LDAP::User, lib: true do
let(:ldap_user) { Gitlab::LDAP::User.new(auth_hash) }
let(:gl_user) { ldap_user.gl_user }
let(:info) do
diff --git a/spec/lib/gitlab/lfs/lfs_router_spec.rb b/spec/lib/gitlab/lfs/lfs_router_spec.rb
index cebcb5bc887..5852b31ab3a 100644
--- a/spec/lib/gitlab/lfs/lfs_router_spec.rb
+++ b/spec/lib/gitlab/lfs/lfs_router_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Lfs::Router do
+describe Gitlab::Lfs::Router, lib: true do
let(:project) { create(:project) }
let(:public_project) { create(:project, :public) }
let(:forked_project) { fork_project(public_project, user) }
@@ -26,113 +26,52 @@ describe Gitlab::Lfs::Router do
let(:sample_oid) { "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80" }
let(:sample_size) { 499013 }
+ let(:respond_with_deprecated) {[ 501, { "Content-Type"=>"application/json; charset=utf-8" }, ["{\"message\":\"Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]}
+ let(:respond_with_disabled) {[ 501, { "Content-Type"=>"application/json; charset=utf-8" }, ["{\"message\":\"Git LFS is not enabled on this GitLab server, contact your admin.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]}
describe 'when lfs is disabled' do
before do
allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
- env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}"
+ env['REQUEST_METHOD'] = 'POST'
+ body = {
+ 'objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078
+ },
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }
+ ],
+ 'operation' => 'upload'
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
end
it 'responds with 501' do
- respond_with_disabled = [ 501,
- { "Content-Type"=>"application/vnd.git-lfs+json" },
- ["{\"message\":\"Git LFS is not enabled on this GitLab server, contact your admin.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]
- ]
expect(lfs_router_auth.try_call).to match_array(respond_with_disabled)
end
end
- describe 'when fetching lfs object' do
+ describe 'when fetching lfs object using deprecated API' do
before do
enable_lfs
- env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8"
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}"
end
- describe 'when user is authenticated' do
- context 'and user has project download access' do
- before do
- @auth = authorize(user)
- env["HTTP_AUTHORIZATION"] = @auth
- project.lfs_objects << lfs_object
- project.team << [user, :master]
- end
-
- it "responds with status 200" do
- expect(lfs_router_auth.try_call.first).to eq(200)
- end
-
- it "responds with download hypermedia" do
- json_response = ActiveSupport::JSON.decode(lfs_router_auth.try_call.last.first)
-
- expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
- expect(json_response['_links']['download']['header']).to eq("Authorization" => @auth, "Accept" => "application/vnd.git-lfs+json; charset=utf-8")
- end
- end
-
- context 'and user does not have project access' do
- it "responds with status 403" do
- expect(lfs_router_auth.try_call.first).to eq(403)
- end
- end
- end
-
- describe 'when user is unauthenticated' do
- context 'and user does not have download access' do
- it "responds with status 401" do
- expect(lfs_router_noauth.try_call.first).to eq(401)
- end
- end
-
- context 'and user has download access' do
- before do
- project.team << [user, :master]
- end
-
- it "responds with status 401" do
- expect(lfs_router_noauth.try_call.first).to eq(401)
- end
- end
+ it 'responds with 501' do
+ expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated)
end
+ end
- describe 'and project is public' do
- context 'and project has access to the lfs object' do
- before do
- public_project.lfs_objects << lfs_object
- end
-
- context 'and user is authenticated' do
- it "responds with status 200 and sends download hypermedia" do
- expect(lfs_router_public_auth.try_call.first).to eq(200)
- json_response = ActiveSupport::JSON.decode(lfs_router_public_auth.try_call.last.first)
-
- expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{public_project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
- expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8")
- end
- end
-
- context 'and user is unauthenticated' do
- it "responds with status 200 and sends download hypermedia" do
- expect(lfs_router_public_noauth.try_call.first).to eq(200)
- json_response = ActiveSupport::JSON.decode(lfs_router_public_noauth.try_call.last.first)
-
- expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{public_project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
- expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8")
- end
- end
- end
-
- context 'and project does not have access to the lfs object' do
- it "responds with status 404" do
- expect(lfs_router_public_auth.try_call.first).to eq(404)
- end
- end
+ describe 'when fetching lfs object' do
+ before do
+ enable_lfs
+ env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8"
+ env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}"
end
describe 'and request comes from gitlab-workhorse' do
- before do
- env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}"
- end
context 'without user being authorized' do
it "responds with status 401" do
expect(lfs_router_noauth.try_call.first).to eq(401)
@@ -173,200 +112,376 @@ describe Gitlab::Lfs::Router do
end
end
end
+ end
- describe 'from a forked public project' do
- before do
- env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8"
- env["PATH_INFO"] = "#{forked_project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}"
- end
+ describe 'when handling lfs request using deprecated API' do
+ before do
+ enable_lfs
+ env['REQUEST_METHOD'] = 'POST'
+ env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects"
+ end
+
+ it 'responds with 501' do
+ expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated)
+ end
+ end
+
+ describe 'when handling lfs batch request' do
+ before do
+ enable_lfs
+ env['REQUEST_METHOD'] = 'POST'
+ env['PATH_INFO'] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
+ end
+
+ describe 'download' do
+ describe 'when user is authenticated' do
+ before do
+ body = { 'operation' => 'download',
+ 'objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ end
- context "when fetching a lfs object" do
- context "and user has project download access" do
+ describe 'when user has download access' do
before do
- public_project.lfs_objects << lfs_object
+ @auth = authorize(user)
+ env["HTTP_AUTHORIZATION"] = @auth
+ project.team << [user, :reporter]
end
- it "can download the lfs object" do
- expect(lfs_router_forked_auth.try_call.first).to eq(200)
- json_response = ActiveSupport::JSON.decode(lfs_router_forked_auth.try_call.last.first)
+ context 'when downloading an lfs object that is assigned to our project' do
+ before do
+ project.lfs_objects << lfs_object
+ end
+
+ it 'responds with status 200 and href to download' do
+ response = lfs_router_auth.try_call
+ expect(response.first).to eq(200)
+ response_body = ActiveSupport::JSON.decode(response.last.first)
- expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{forked_project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}")
- expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8")
+ expect(response_body).to eq('objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'actions' => {
+ 'download' => {
+ 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
+ 'header' => { 'Authorization' => @auth }
+ }
+ }
+ }])
+ end
end
- end
- context "and user is not authenticated but project is public" do
- before do
- public_project.lfs_objects << lfs_object
+ context 'when downloading an lfs object that is assigned to other project' do
+ before do
+ public_project.lfs_objects << lfs_object
+ end
+
+ it 'responds with status 200 and error message' do
+ response = lfs_router_auth.try_call
+ expect(response.first).to eq(200)
+ response_body = ActiveSupport::JSON.decode(response.last.first)
+
+ expect(response_body).to eq('objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'error' => {
+ 'code' => 404,
+ 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ }
+ }])
+ end
end
- it "can download the lfs object" do
- expect(lfs_router_forked_auth.try_call.first).to eq(200)
+ context 'when downloading a lfs object that does not exist' do
+ before do
+ body = { 'operation' => 'download',
+ 'objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078
+ }]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ end
+
+ it "responds with status 200 and error message" do
+ response = lfs_router_auth.try_call
+ expect(response.first).to eq(200)
+ response_body = ActiveSupport::JSON.decode(response.last.first)
+
+ expect(response_body).to eq('objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078,
+ 'error' => {
+ 'code' => 404,
+ 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ }
+ }])
+ end
+ end
+
+ context 'when downloading one new and one existing lfs object' do
+ before do
+ body = { 'operation' => 'download',
+ 'objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078
+ },
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }
+ ]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ project.lfs_objects << lfs_object
+ end
+
+ it "responds with status 200 with upload hypermedia link for the new object" do
+ response = lfs_router_auth.try_call
+ expect(response.first).to eq(200)
+ response_body = ActiveSupport::JSON.decode(response.last.first)
+
+ expect(response_body).to eq('objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078,
+ 'error' => {
+ 'code' => 404,
+ 'message' => "Object does not exist on the server or you don't have permissions to access it",
+ }
+ },
+ { 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'actions' => {
+ 'download' => {
+ 'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
+ 'header' => { 'Authorization' => @auth }
+ }
+ }
+ }])
+ end
end
end
- context "and user has project download access" do
+ context 'when user does is not member of the project' do
before do
- env["PATH_INFO"] = "#{forked_project.repository.path_with_namespace}.git/info/lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897"
- @auth = ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
+ @auth = authorize(user)
env["HTTP_AUTHORIZATION"] = @auth
- lfs_object_two = create(:lfs_object, :with_file, oid: "91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897", size: 1575078)
- public_project.lfs_objects << lfs_object_two
+ project.team << [user, :guest]
end
- it "can get a lfs object that is not in the forked project" do
- expect(lfs_router_forked_auth.try_call.first).to eq(200)
-
- json_response = ActiveSupport::JSON.decode(lfs_router_forked_auth.try_call.last.first)
- expect(json_response['_links']['download']['href']).to eq("#{Gitlab.config.gitlab.url}/#{forked_project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
- expect(json_response['_links']['download']['header']).to eq("Accept" => "application/vnd.git-lfs+json; charset=utf-8", "Authorization" => @auth)
+ it 'responds with 403' do
+ expect(lfs_router_auth.try_call.first).to eq(403)
end
end
- context "and user has project download access" do
+ context 'when user does not have download access' do
before do
- env["PATH_INFO"] = "#{forked_project.repository.path_with_namespace}.git/info/lfs/objects/267c8b1d876743971e3a9978405818ff5ca731c4c870b06507619cd9b1847b6b"
- lfs_object_three = create(:lfs_object, :with_file, oid: "267c8b1d876743971e3a9978405818ff5ca731c4c870b06507619cd9b1847b6b", size: 127192524)
- project.lfs_objects << lfs_object_three
+ @auth = authorize(user)
+ env["HTTP_AUTHORIZATION"] = @auth
+ project.team << [user, :guest]
end
- it "cannot get a lfs object that is not in the project" do
- expect(lfs_router_forked_auth.try_call.first).to eq(404)
+ it 'responds with 403' do
+ expect(lfs_router_auth.try_call.first).to eq(403)
end
end
end
- end
- end
-
- describe 'when initiating pushing of the lfs object' do
- before do
- enable_lfs
- env['REQUEST_METHOD'] = 'POST'
- env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
- end
-
- describe 'when user is authenticated' do
- before do
- body = { 'objects' => [{
- 'oid' => sample_oid,
- 'size' => sample_size
- }]
- }.to_json
- env['rack.input'] = StringIO.new(body)
- end
- describe 'when user has project push access' do
+ context 'when user is not authenticated' do
before do
- @auth = authorize(user)
- env["HTTP_AUTHORIZATION"] = @auth
- project.team << [user, :master]
+ body = { 'operation' => 'download',
+ 'objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }],
+
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
end
- context 'when pushing an lfs object that already exists' do
+ describe 'is accessing public project' do
before do
public_project.lfs_objects << lfs_object
end
- it "responds with status 200 and links the object to the project" do
- response_body = lfs_router_auth.try_call.last
- response = ActiveSupport::JSON.decode(response_body.first)
+ it 'responds with status 200 and href to download' do
+ response = lfs_router_public_noauth.try_call
+ expect(response.first).to eq(200)
+ response_body = ActiveSupport::JSON.decode(response.last.first)
- expect(response['objects']).to be_kind_of(Array)
- expect(response['objects'].first['oid']).to eq(sample_oid)
- expect(response['objects'].first['size']).to eq(sample_size)
- expect(lfs_object.projects.pluck(:id)).to_not include(project.id)
- expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
- expect(response['objects'].first).to have_key('_links')
+ expect(response_body).to eq('objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size,
+ 'actions' => {
+ 'download' => {
+ 'href' => "#{public_project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
+ 'header' => {}
+ }
+ }
+ }])
end
end
- context 'when pushing a lfs object that does not exist' do
+ describe 'is accessing non-public project' do
before do
- body = {
- 'objects' => [{
- 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- }]
- }.to_json
- env['rack.input'] = StringIO.new(body)
+ project.lfs_objects << lfs_object
end
- it "responds with status 200 and upload hypermedia link" do
- response = lfs_router_auth.try_call
- expect(response.first).to eq(200)
-
- response_body = ActiveSupport::JSON.decode(response.last.first)
- expect(response_body['objects']).to be_kind_of(Array)
- expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
- expect(response_body['objects'].first['size']).to eq(1575078)
- expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
- expect(response_body['objects'].first['_links']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
- expect(response_body['objects'].first['_links']['upload']['header']).to eq("Authorization" => @auth)
+ it 'responds with authorization required' do
+ expect(lfs_router_noauth.try_call.first).to eq(401)
end
end
+ end
+ end
- context 'when pushing one new and one existing lfs object' do
+ describe 'upload' do
+ describe 'when user is authenticated' do
+ before do
+ body = { 'operation' => 'upload',
+ 'objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ end
+
+ describe 'when user has project push access' do
before do
- body = {
- 'objects' => [
- { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
- 'size' => 1575078
- },
- { 'oid' => sample_oid,
- 'size' => sample_size
- }
- ]
- }.to_json
- env['rack.input'] = StringIO.new(body)
- public_project.lfs_objects << lfs_object
+ @auth = authorize(user)
+ env["HTTP_AUTHORIZATION"] = @auth
+ project.team << [user, :developer]
end
- it "responds with status 200 with upload hypermedia link for the new object" do
- response = lfs_router_auth.try_call
- expect(response.first).to eq(200)
+ context 'when pushing an lfs object that already exists' do
+ before do
+ public_project.lfs_objects << lfs_object
+ end
- response_body = ActiveSupport::JSON.decode(response.last.first)
- expect(response_body['objects']).to be_kind_of(Array)
+ it "responds with status 200 and links the object to the project" do
+ response_body = lfs_router_auth.try_call.last
+ response = ActiveSupport::JSON.decode(response_body.first)
+ expect(response['objects']).to be_kind_of(Array)
+ expect(response['objects'].first['oid']).to eq(sample_oid)
+ expect(response['objects'].first['size']).to eq(sample_size)
+ expect(lfs_object.projects.pluck(:id)).to_not include(project.id)
+ expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
+ expect(response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}")
+ expect(response['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
+ end
+ end
- expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
- expect(response_body['objects'].first['size']).to eq(1575078)
- expect(response_body['objects'].first['_links']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
- expect(response_body['objects'].first['_links']['upload']['header']).to eq("Authorization" => @auth)
+ context 'when pushing a lfs object that does not exist' do
+ before do
+ body = { 'operation' => 'upload',
+ 'objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078
+ }]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ end
- expect(response_body['objects'].last['oid']).to eq(sample_oid)
- expect(response_body['objects'].last['size']).to eq(sample_size)
- expect(lfs_object.projects.pluck(:id)).to_not include(project.id)
- expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
- expect(response_body['objects'].last).to have_key('_links')
+ it "responds with status 200 and upload hypermedia link" do
+ response = lfs_router_auth.try_call
+ expect(response.first).to eq(200)
+
+ response_body = ActiveSupport::JSON.decode(response.last.first)
+ expect(response_body['objects']).to be_kind_of(Array)
+ expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
+ expect(response_body['objects'].first['size']).to eq(1575078)
+ expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
+ expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
+ expect(response_body['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
+ end
+ end
+
+ context 'when pushing one new and one existing lfs object' do
+ before do
+ body = { 'operation' => 'upload',
+ 'objects' => [
+ { 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
+ 'size' => 1575078
+ },
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }
+ ]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ project.lfs_objects << lfs_object
+ end
+
+ it "responds with status 200 with upload hypermedia link for the new object" do
+ response = lfs_router_auth.try_call
+ expect(response.first).to eq(200)
+
+ response_body = ActiveSupport::JSON.decode(response.last.first)
+ expect(response_body['objects']).to be_kind_of(Array)
+
+ expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
+ expect(response_body['objects'].first['size']).to eq(1575078)
+ expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
+ expect(response_body['objects'].first['actions']['upload']['header']).to eq("Authorization" => @auth)
+
+ expect(response_body['objects'].last['oid']).to eq(sample_oid)
+ expect(response_body['objects'].last['size']).to eq(sample_size)
+ expect(response_body['objects'].last).to_not have_key('actions')
+ end
end
end
- end
- context 'when user does not have push access' do
- it 'responds with 403' do
- expect(lfs_router_auth.try_call.first).to eq(403)
+ context 'when user does not have push access' do
+ it 'responds with 403' do
+ expect(lfs_router_auth.try_call.first).to eq(403)
+ end
end
end
- end
- context 'when user is not authenticated' do
- context 'when user has push access' do
+ context 'when user is not authenticated' do
before do
- project.team << [user, :master]
+ env['rack.input'] = StringIO.new(
+ { 'objects' => [], 'operation' => 'upload' }.to_json
+ )
end
- it "responds with status 401" do
- expect(lfs_router_public_noauth.try_call.first).to eq(401)
+ context 'when user has push access' do
+ before do
+ project.team << [user, :master]
+ end
+
+ it "responds with status 401" do
+ expect(lfs_router_public_noauth.try_call.first).to eq(401)
+ end
end
- end
- context 'when user does not have push access' do
- it "responds with status 401" do
- expect(lfs_router_public_noauth.try_call.first).to eq(401)
+ context 'when user does not have push access' do
+ it "responds with status 401" do
+ expect(lfs_router_public_noauth.try_call.first).to eq(401)
+ end
end
end
end
+
+ describe 'unsupported' do
+ before do
+ body = { 'operation' => 'other',
+ 'objects' => [
+ { 'oid' => sample_oid,
+ 'size' => sample_size
+ }]
+ }.to_json
+ env['rack.input'] = StringIO.new(body)
+ end
+
+ it 'responds with status 404' do
+ expect(lfs_router_public_noauth.try_call.first).to eq(404)
+ end
+ end
end
describe 'when pushing a lfs object' do
diff --git a/spec/lib/gitlab/markdown/autolink_filter_spec.rb b/spec/lib/gitlab/markdown/autolink_filter_spec.rb
deleted file mode 100644
index 26332ba5217..00000000000
--- a/spec/lib/gitlab/markdown/autolink_filter_spec.rb
+++ /dev/null
@@ -1,114 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe AutolinkFilter do
- include FilterSpecHelper
-
- let(:link) { 'http://about.gitlab.com/' }
-
- it 'does nothing when :autolink is false' do
- exp = act = link
- expect(filter(act, autolink: false).to_html).to eq exp
- end
-
- it 'does nothing with non-link text' do
- exp = act = 'This text contains no links to autolink'
- expect(filter(act).to_html).to eq exp
- end
-
- context 'Rinku schemes' do
- it 'autolinks http' do
- doc = filter("See #{link}")
- expect(doc.at_css('a').text).to eq link
- expect(doc.at_css('a')['href']).to eq link
- end
-
- it 'autolinks https' do
- link = 'https://google.com/'
- doc = filter("See #{link}")
-
- expect(doc.at_css('a').text).to eq link
- expect(doc.at_css('a')['href']).to eq link
- end
-
- it 'autolinks ftp' do
- link = 'ftp://ftp.us.debian.org/debian/'
- doc = filter("See #{link}")
-
- expect(doc.at_css('a').text).to eq link
- expect(doc.at_css('a')['href']).to eq link
- end
-
- it 'autolinks short URLs' do
- link = 'http://localhost:3000/'
- doc = filter("See #{link}")
-
- expect(doc.at_css('a').text).to eq link
- expect(doc.at_css('a')['href']).to eq link
- end
-
- it 'accepts link_attr options' do
- doc = filter("See #{link}", link_attr: { class: 'custom' })
-
- expect(doc.at_css('a')['class']).to eq 'custom'
- end
-
- described_class::IGNORE_PARENTS.each do |elem|
- it "ignores valid links contained inside '#{elem}' element" do
- exp = act = "<#{elem}>See #{link}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
- end
-
- context 'other schemes' do
- let(:link) { 'foo://bar.baz/' }
-
- it 'autolinks smb' do
- link = 'smb:///Volumes/shared/foo.pdf'
- doc = filter("See #{link}")
-
- expect(doc.at_css('a').text).to eq link
- expect(doc.at_css('a')['href']).to eq link
- end
-
- it 'autolinks irc' do
- link = 'irc://irc.freenode.net/git'
- doc = filter("See #{link}")
-
- expect(doc.at_css('a').text).to eq link
- expect(doc.at_css('a')['href']).to eq link
- end
-
- it 'does not include trailing punctuation' do
- doc = filter("See #{link}.")
- expect(doc.at_css('a').text).to eq link
-
- doc = filter("See #{link}, ok?")
- expect(doc.at_css('a').text).to eq link
-
- doc = filter("See #{link}...")
- expect(doc.at_css('a').text).to eq link
- end
-
- it 'does not include trailing HTML entities' do
- doc = filter("See &lt;&lt;&lt;#{link}&gt;&gt;&gt;")
-
- expect(doc.at_css('a')['href']).to eq link
- expect(doc.text).to eq "See <<<#{link}>>>"
- end
-
- it 'accepts link_attr options' do
- doc = filter("See #{link}", link_attr: { class: 'custom' })
- expect(doc.at_css('a')['class']).to eq 'custom'
- end
-
- described_class::IGNORE_PARENTS.each do |elem|
- it "ignores valid links contained inside '#{elem}' element" do
- exp = act = "<#{elem}>See #{link}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
deleted file mode 100644
index e5b8d723fe5..00000000000
--- a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
+++ /dev/null
@@ -1,145 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe CommitRangeReferenceFilter do
- include FilterSpecHelper
-
- let(:project) { create(:project, :public) }
- let(:commit1) { project.commit }
- let(:commit2) { project.commit("HEAD~2") }
-
- let(:range) { CommitRange.new("#{commit1.id}...#{commit2.id}") }
- let(:range2) { CommitRange.new("#{commit1.id}..#{commit2.id}") }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Commit Range #{range.to_reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'internal reference' do
- let(:reference) { range.to_reference }
- let(:reference2) { range2.to_reference }
-
- it 'links to a valid two-dot reference' do
- doc = filter("See #{reference2}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_compare_url(project.namespace, project, range2.to_param)
- end
-
- it 'links to a valid three-dot reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_compare_url(project.namespace, project, range.to_param)
- end
-
- it 'links to a valid short ID' do
- reference = "#{commit1.short_id}...#{commit2.id}"
- reference2 = "#{commit1.id}...#{commit2.short_id}"
-
- exp = commit1.short_id + '...' + commit2.short_id
-
- expect(filter("See #{reference}").css('a').first.text).to eq exp
- expect(filter("See #{reference2}").css('a').first.text).to eq exp
- end
-
- it 'links with adjacent text' do
- doc = filter("See (#{reference}.)")
-
- exp = Regexp.escape(range.to_s)
- expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
- end
-
- it 'ignores invalid commit IDs' do
- exp = act = "See #{commit1.id.reverse}...#{commit2.id}"
-
- expect(project).to receive(:valid_repo?).and_return(true)
- expect(project.repository).to receive(:commit).with(commit1.id.reverse)
- expect(filter(act).to_html).to eq exp
- end
-
- it 'includes a title attribute' do
- doc = filter("See #{reference}")
- expect(doc.css('a').first.attr('title')).to eq range.reference_title
- end
-
- it 'includes default classes' do
- doc = filter("See #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit_range'
- end
-
- it 'includes a data-project attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-project')
- expect(link.attr('data-project')).to eq project.id.to_s
- end
-
- it 'includes a data-commit-range attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-commit-range')
- expect(link.attr('data-commit-range')).to eq range.to_reference
- end
-
- it 'supports an :only_path option' do
- doc = filter("See #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_compare_url(project.namespace, project, from: commit1.id, to: commit2.id, only_path: true)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit_range]).not_to be_empty
- end
- end
-
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
- let(:reference) { range.to_reference(project) }
-
- before do
- range.project = project2
- end
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
-
- exp = Regexp.escape("#{project2.to_reference}@#{range.to_s}")
- expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
- end
-
- it 'ignores invalid commit IDs on the referenced project' do
- exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
- expect(filter(act).to_html).to eq exp
-
- exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
- expect(filter(act).to_html).to eq exp
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit_range]).not_to be_empty
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
deleted file mode 100644
index d080efbf3d4..00000000000
--- a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
+++ /dev/null
@@ -1,135 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe CommitReferenceFilter do
- include FilterSpecHelper
-
- let(:project) { create(:project, :public) }
- let(:commit) { project.commit }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Commit #{commit.id}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'internal reference' do
- let(:reference) { commit.id }
-
- # Let's test a variety of commit SHA sizes just to be paranoid
- [6, 8, 12, 18, 20, 32, 40].each do |size|
- it "links to a valid reference of #{size} characters" do
- doc = filter("See #{reference[0...size]}")
-
- expect(doc.css('a').first.text).to eq commit.short_id
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_commit_url(project.namespace, project, reference)
- end
- end
-
- it 'always uses the short ID as the link text' do
- doc = filter("See #{commit.id}")
- expect(doc.text).to eq "See #{commit.short_id}"
-
- doc = filter("See #{commit.id[0...6]}")
- expect(doc.text).to eq "See #{commit.short_id}"
- end
-
- it 'links with adjacent text' do
- doc = filter("See (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{commit.short_id}<\/a>\.\)/)
- end
-
- it 'ignores invalid commit IDs' do
- invalid = invalidate_reference(reference)
- exp = act = "See #{invalid}"
-
- expect(project).to receive(:valid_repo?).and_return(true)
- expect(project.repository).to receive(:commit).with(invalid)
- expect(filter(act).to_html).to eq exp
- end
-
- it 'includes a title attribute' do
- doc = filter("See #{reference}")
- expect(doc.css('a').first.attr('title')).to eq commit.link_title
- end
-
- it 'escapes the title attribute' do
- allow_any_instance_of(Commit).to receive(:title).and_return(%{"></a>whatever<a title="})
-
- doc = filter("See #{reference}")
- expect(doc.text).to eq "See #{commit.short_id}"
- end
-
- it 'includes default classes' do
- doc = filter("See #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit'
- end
-
- it 'includes a data-project attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-project')
- expect(link.attr('data-project')).to eq project.id.to_s
- end
-
- it 'includes a data-commit attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-commit')
- expect(link.attr('data-commit')).to eq commit.id
- end
-
- it 'supports an :only_path context' do
- doc = filter("See #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_commit_url(project.namespace, project, reference, only_path: true)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit]).not_to be_empty
- end
- end
-
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
- let(:commit) { project2.commit }
- let(:reference) { commit.to_reference(project) }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
-
- exp = Regexp.escape(project2.to_reference)
- expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
- end
-
- it 'ignores invalid commit IDs on the referenced project' do
- exp = act = "Committed #{invalidate_reference(reference)}"
- expect(filter(act).to_html).to eq exp
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("See #{reference}")
- expect(result[:references][:commit]).not_to be_empty
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb b/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
deleted file mode 100644
index 8d4f9e403a6..00000000000
--- a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe CrossProjectReference do
- include described_class
-
- describe '#project_from_ref' do
- context 'when no project was referenced' do
- it 'returns the project from context' do
- project = double
-
- allow(self).to receive(:context).and_return({ project: project })
-
- expect(project_from_ref(nil)).to eq project
- end
- end
-
- context 'when referenced project does not exist' do
- it 'returns nil' do
- expect(project_from_ref('invalid/reference')).to be_nil
- end
- end
-
- context 'when referenced project exists' do
- it 'returns the referenced project' do
- project2 = double('referenced project')
-
- expect(Project).to receive(:find_with_namespace).
- with('cross/reference').and_return(project2)
-
- expect(project_from_ref('cross/reference')).to eq project2
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/emoji_filter_spec.rb b/spec/lib/gitlab/markdown/emoji_filter_spec.rb
deleted file mode 100644
index 11efd9bb4cd..00000000000
--- a/spec/lib/gitlab/markdown/emoji_filter_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe EmojiFilter do
- include FilterSpecHelper
-
- before do
- ActionController::Base.asset_host = 'https://foo.com'
- end
-
- it 'replaces supported emoji' do
- doc = filter('<p>:heart:</p>')
- expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/emoji/2764.png'
- end
-
- it 'ignores unsupported emoji' do
- exp = act = '<p>:foo:</p>'
- doc = filter(act)
- expect(doc.to_html).to match Regexp.escape(exp)
- end
-
- it 'correctly encodes the URL' do
- doc = filter('<p>:+1:</p>')
- expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/emoji/1F44D.png'
- end
-
- it 'matches at the start of a string' do
- doc = filter(':+1:')
- expect(doc.css('img').size).to eq 1
- end
-
- it 'matches at the end of a string' do
- doc = filter('This gets a :-1:')
- expect(doc.css('img').size).to eq 1
- end
-
- it 'matches with adjacent text' do
- doc = filter('+1 (:+1:)')
- expect(doc.css('img').size).to eq 1
- end
-
- it 'matches multiple emoji in a row' do
- doc = filter(':see_no_evil::hear_no_evil::speak_no_evil:')
- expect(doc.css('img').size).to eq 3
- end
-
- it 'has a title attribute' do
- doc = filter(':-1:')
- expect(doc.css('img').first.attr('title')).to eq ':-1:'
- end
-
- it 'has an alt attribute' do
- doc = filter(':-1:')
- expect(doc.css('img').first.attr('alt')).to eq ':-1:'
- end
-
- it 'has an align attribute' do
- doc = filter(':8ball:')
- expect(doc.css('img').first.attr('align')).to eq 'absmiddle'
- end
-
- it 'has an emoji class' do
- doc = filter(':cat:')
- expect(doc.css('img').first.attr('class')).to eq 'emoji'
- end
-
- it 'has height and width attributes' do
- doc = filter(':dog:')
- img = doc.css('img').first
-
- expect(img.attr('width')).to eq '20'
- expect(img.attr('height')).to eq '20'
- end
-
- it 'keeps whitespace intact' do
- doc = filter('This deserves a :+1:, big time.')
-
- expect(doc.to_html).to match(/^This deserves a <img.+>, big time\.\z/)
- end
-
- it 'uses a custom asset_root context' do
- root = Gitlab.config.gitlab.url + 'gitlab/root'
-
- doc = filter(':smile:', asset_root: root)
- expect(doc.css('img').first.attr('src')).to start_with(root)
- end
-
- it 'uses a custom asset_host context' do
- ActionController::Base.asset_host = 'https://cdn.example.com'
-
- doc = filter(':frowning:', asset_host: 'https://this-is-ignored-i-guess?')
- expect(doc.css('img').first.attr('src')).to start_with('https://cdn.example.com')
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb
deleted file mode 100644
index d8c2970b6bd..00000000000
--- a/spec/lib/gitlab/markdown/external_issue_reference_filter_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe ExternalIssueReferenceFilter do
- include FilterSpecHelper
-
- def helper
- IssuesHelper
- end
-
- let(:project) { create(:jira_project) }
-
- context 'JIRA issue references' do
- let(:issue) { ExternalIssue.new('JIRA-123', project) }
- let(:reference) { issue.to_reference }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Issue #{reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- it 'ignores valid references when using default tracker' do
- expect(project).to receive(:default_issues_tracker?).and_return(true)
-
- exp = act = "Issue #{reference}"
- expect(filter(act).to_html).to eq exp
- end
-
- it 'links to a valid reference' do
- doc = filter("Issue #{reference}")
- expect(doc.css('a').first.attr('href'))
- .to eq helper.url_for_issue(reference, project)
- end
-
- it 'links to the external tracker' do
- doc = filter("Issue #{reference}")
- link = doc.css('a').first.attr('href')
-
- expect(link).to eq "http://jira.example/browse/#{reference}"
- end
-
- it 'links with adjacent text' do
- doc = filter("Issue (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
- end
-
- it 'includes a title attribute' do
- doc = filter("Issue #{reference}")
- expect(doc.css('a').first.attr('title')).to eq "Issue in JIRA tracker"
- end
-
- it 'escapes the title attribute' do
- allow(project.external_issue_tracker).to receive(:title).
- and_return(%{"></a>whatever<a title="})
-
- doc = filter("Issue #{reference}")
- expect(doc.text).to eq "Issue #{reference}"
- end
-
- it 'includes default classes' do
- doc = filter("Issue #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
- end
-
- it 'supports an :only_path context' do
- doc = filter("Issue #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).to eq helper.url_for_issue("#{reference}", project, only_path: true)
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/external_link_filter_spec.rb b/spec/lib/gitlab/markdown/external_link_filter_spec.rb
deleted file mode 100644
index a040b34577b..00000000000
--- a/spec/lib/gitlab/markdown/external_link_filter_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe ExternalLinkFilter do
- include FilterSpecHelper
-
- it 'ignores elements without an href attribute' do
- exp = act = %q(<a id="ignored">Ignore Me</a>)
- expect(filter(act).to_html).to eq exp
- end
-
- it 'ignores non-HTTP(S) links' do
- exp = act = %q(<a href="irc://irc.freenode.net/gitlab">IRC</a>)
- expect(filter(act).to_html).to eq exp
- end
-
- it 'skips internal links' do
- internal = Gitlab.config.gitlab.url
- exp = act = %Q(<a href="#{internal}/sign_in">Login</a>)
- expect(filter(act).to_html).to eq exp
- end
-
- it 'adds rel="nofollow" to external links' do
- act = %q(<a href="https://google.com/">Google</a>)
- doc = filter(act)
-
- expect(doc.at_css('a')).to have_attribute('rel')
- expect(doc.at_css('a')['rel']).to eq 'nofollow'
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
deleted file mode 100644
index 94c80ae6611..00000000000
--- a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
+++ /dev/null
@@ -1,139 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe IssueReferenceFilter do
- include FilterSpecHelper
-
- def helper
- IssuesHelper
- end
-
- let(:project) { create(:empty_project, :public) }
- let(:issue) { create(:issue, project: project) }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Issue #{issue.to_reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'internal reference' do
- let(:reference) { issue.to_reference }
-
- it 'ignores valid references when using non-default tracker' do
- expect(project).to receive(:get_issue).with(issue.iid).and_return(nil)
-
- exp = act = "Issue #{reference}"
- expect(filter(act).to_html).to eq exp
- end
-
- it 'links to a valid reference' do
- doc = filter("Fixed #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq helper.url_for_issue(issue.iid, project)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid issue IDs' do
- invalid = invalidate_reference(reference)
- exp = act = "Fixed #{invalid}"
-
- expect(filter(act).to_html).to eq exp
- end
-
- it 'includes a title attribute' do
- doc = filter("Issue #{reference}")
- expect(doc.css('a').first.attr('title')).to eq "Issue: #{issue.title}"
- end
-
- it 'escapes the title attribute' do
- issue.update_attribute(:title, %{"></a>whatever<a title="})
-
- doc = filter("Issue #{reference}")
- expect(doc.text).to eq "Issue #{reference}"
- end
-
- it 'includes default classes' do
- doc = filter("Issue #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
- end
-
- it 'includes a data-project attribute' do
- doc = filter("Issue #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-project')
- expect(link.attr('data-project')).to eq project.id.to_s
- end
-
- it 'includes a data-issue attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-issue')
- expect(link.attr('data-issue')).to eq issue.id.to_s
- end
-
- it 'supports an :only_path context' do
- doc = filter("Issue #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq helper.url_for_issue(issue.iid, project, only_path: true)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
- end
-
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:empty_project, :public, namespace: namespace) }
- let(:issue) { create(:issue, project: project2) }
- let(:reference) { issue.to_reference(project) }
-
- it 'ignores valid references when cross-reference project uses external tracker' do
- expect_any_instance_of(Project).to receive(:get_issue).
- with(issue.iid).and_return(nil)
-
- exp = act = "Issue #{reference}"
- expect(filter(act).to_html).to eq exp
- end
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq helper.url_for_issue(issue.iid, project2)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid issue IDs on the referenced project' do
- exp = act = "Fixed #{invalidate_reference(reference)}"
-
- expect(filter(act).to_html).to eq exp
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
deleted file mode 100644
index fc21b65a843..00000000000
--- a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
+++ /dev/null
@@ -1,144 +0,0 @@
-require 'spec_helper'
-require 'html/pipeline'
-
-module Gitlab::Markdown
- describe LabelReferenceFilter do
- include FilterSpecHelper
-
- let(:project) { create(:empty_project, :public) }
- let(:label) { create(:label, project: project) }
- let(:reference) { label.to_reference }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Label #{reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- it 'includes default classes' do
- doc = filter("Label #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label'
- end
-
- it 'includes a data-project attribute' do
- doc = filter("Label #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-project')
- expect(link.attr('data-project')).to eq project.id.to_s
- end
-
- it 'includes a data-label attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-label')
- expect(link.attr('data-label')).to eq label.id.to_s
- end
-
- it 'supports an :only_path context' do
- doc = filter("Label #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_issues_path(project.namespace, project, label_name: label.name)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Label #{reference}")
- expect(result[:references][:label]).to eq [label]
- end
-
- describe 'label span element' do
- it 'includes default classes' do
- doc = filter("Label #{reference}")
- expect(doc.css('a span').first.attr('class')).to eq 'label color-label'
- end
-
- it 'includes a style attribute' do
- doc = filter("Label #{reference}")
- expect(doc.css('a span').first.attr('style')).to match(/\Abackground-color: #\h{6}; color: #\h{6}\z/)
- end
- end
-
- context 'Integer-based references' do
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).to eq urls.
- namespace_project_issues_url(project.namespace, project, label_name: label.name)
- end
-
- it 'links with adjacent text' do
- doc = filter("Label (#{reference}.)")
- expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
- end
-
- it 'ignores invalid label IDs' do
- exp = act = "Label #{invalidate_reference(reference)}"
-
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'String-based single-word references' do
- let(:label) { create(:label, name: 'gfm', project: project) }
- let(:reference) { "#{Label.reference_prefix}#{label.name}" }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).to eq urls.
- namespace_project_issues_url(project.namespace, project, label_name: label.name)
- expect(doc.text).to eq 'See gfm'
- end
-
- it 'links with adjacent text' do
- doc = filter("Label (#{reference}.)")
- expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
- end
-
- it 'ignores invalid label names' do
- exp = act = "Label #{Label.reference_prefix}#{label.name.reverse}"
-
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'String-based multi-word references in quotes' do
- let(:label) { create(:label, name: 'gfm references', project: project) }
- let(:reference) { label.to_reference(:name) }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).to eq urls.
- namespace_project_issues_url(project.namespace, project, label_name: label.name)
- expect(doc.text).to eq 'See gfm references'
- end
-
- it 'links with adjacent text' do
- doc = filter("Label (#{reference}.)")
- expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
- end
-
- it 'ignores invalid label names' do
- exp = act = %(Label #{Label.reference_prefix}"#{label.name.reverse}")
-
- expect(filter(act).to_html).to eq exp
- end
- end
-
- describe 'edge cases' do
- it 'gracefully handles non-references matching the pattern' do
- exp = act = '(format nil "~0f" 3.0) ; 3.0'
- expect(filter(act).to_html).to eq exp
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
deleted file mode 100644
index 3ef6cdfff33..00000000000
--- a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe MergeRequestReferenceFilter do
- include FilterSpecHelper
-
- let(:project) { create(:project, :public) }
- let(:merge) { create(:merge_request, source_project: project) }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Merge #{merge.to_reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'internal reference' do
- let(:reference) { merge.to_reference }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).to eq urls.
- namespace_project_merge_request_url(project.namespace, project, merge)
- end
-
- it 'links with adjacent text' do
- doc = filter("Merge (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid merge IDs' do
- exp = act = "Merge #{invalidate_reference(reference)}"
-
- expect(filter(act).to_html).to eq exp
- end
-
- it 'includes a title attribute' do
- doc = filter("Merge #{reference}")
- expect(doc.css('a').first.attr('title')).to eq "Merge Request: #{merge.title}"
- end
-
- it 'escapes the title attribute' do
- merge.update_attribute(:title, %{"></a>whatever<a title="})
-
- doc = filter("Merge #{reference}")
- expect(doc.text).to eq "Merge #{reference}"
- end
-
- it 'includes default classes' do
- doc = filter("Merge #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request'
- end
-
- it 'includes a data-project attribute' do
- doc = filter("Merge #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-project')
- expect(link.attr('data-project')).to eq project.id.to_s
- end
-
- it 'includes a data-merge-request attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-merge-request')
- expect(link.attr('data-merge-request')).to eq merge.id.to_s
- end
-
- it 'supports an :only_path context' do
- doc = filter("Merge #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_merge_request_url(project.namespace, project, merge, only_path: true)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Merge #{reference}")
- expect(result[:references][:merge_request]).to eq [merge]
- end
- end
-
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
- let(:merge) { create(:merge_request, source_project: project2) }
- let(:reference) { merge.to_reference(project) }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_merge_request_url(project2.namespace,
- project, merge)
- end
-
- it 'links with adjacent text' do
- doc = filter("Merge (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid merge IDs on the referenced project' do
- exp = act = "Merge #{invalidate_reference(reference)}"
-
- expect(filter(act).to_html).to eq exp
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Merge #{reference}")
- expect(result[:references][:merge_request]).to eq [merge]
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/redactor_filter_spec.rb b/spec/lib/gitlab/markdown/redactor_filter_spec.rb
deleted file mode 100644
index eea3f1cf370..00000000000
--- a/spec/lib/gitlab/markdown/redactor_filter_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe RedactorFilter do
- include ActionView::Helpers::UrlHelper
- include FilterSpecHelper
-
- it 'ignores non-GFM links' do
- html = %(See <a href="https://google.com/">Google</a>)
- doc = filter(html, current_user: double)
-
- expect(doc.css('a').length).to eq 1
- end
-
- def reference_link(data)
- link_to('text', '', class: 'gfm', data: data)
- end
-
- context 'with data-project' do
- it 'removes unpermitted Project references' do
- user = create(:user)
- project = create(:empty_project)
-
- link = reference_link(project: project.id, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
- doc = filter(link, current_user: user)
-
- expect(doc.css('a').length).to eq 0
- end
-
- it 'allows permitted Project references' do
- user = create(:user)
- project = create(:empty_project)
- project.team << [user, :master]
-
- link = reference_link(project: project.id, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
- doc = filter(link, current_user: user)
-
- expect(doc.css('a').length).to eq 1
- end
-
- it 'handles invalid Project references' do
- link = reference_link(project: 12345, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
-
- expect { filter(link) }.not_to raise_error
- end
- end
-
- context "for user references" do
-
- context 'with data-group' do
- it 'removes unpermitted Group references' do
- user = create(:user)
- group = create(:group)
-
- link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
- doc = filter(link, current_user: user)
-
- expect(doc.css('a').length).to eq 0
- end
-
- it 'allows permitted Group references' do
- user = create(:user)
- group = create(:group)
- group.add_developer(user)
-
- link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
- doc = filter(link, current_user: user)
-
- expect(doc.css('a').length).to eq 1
- end
-
- it 'handles invalid Group references' do
- link = reference_link(group: 12345, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
-
- expect { filter(link) }.not_to raise_error
- end
- end
-
- context 'with data-user' do
- it 'allows any User reference' do
- user = create(:user)
-
- link = reference_link(user: user.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
- doc = filter(link)
-
- expect(doc.css('a').length).to eq 1
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb b/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb
deleted file mode 100644
index 4fa473ad191..00000000000
--- a/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe ReferenceGathererFilter do
- include ActionView::Helpers::UrlHelper
- include FilterSpecHelper
-
- def reference_link(data)
- link_to('text', '', class: 'gfm', data: data)
- end
-
- context "for issue references" do
-
- context 'with data-project' do
- it 'removes unpermitted Project references' do
- user = create(:user)
- project = create(:empty_project)
- issue = create(:issue, project: project)
-
- link = reference_link(project: project.id, issue: issue.id, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:issue]).to be_empty
- end
-
- it 'allows permitted Project references' do
- user = create(:user)
- project = create(:empty_project)
- issue = create(:issue, project: project)
- project.team << [user, :master]
-
- link = reference_link(project: project.id, issue: issue.id, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:issue]).to eq([issue])
- end
-
- it 'handles invalid Project references' do
- link = reference_link(project: 12345, issue: 12345, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
-
- expect { pipeline_result(link) }.not_to raise_error
- end
- end
- end
-
- context "for user references" do
-
- context 'with data-group' do
- it 'removes unpermitted Group references' do
- user = create(:user)
- group = create(:group)
-
- link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:user]).to be_empty
- end
-
- it 'allows permitted Group references' do
- user = create(:user)
- group = create(:group)
- group.add_developer(user)
-
- link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
- result = pipeline_result(link, current_user: user)
-
- expect(result[:references][:user]).to eq([user])
- end
-
- it 'handles invalid Group references' do
- link = reference_link(group: 12345, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
-
- expect { pipeline_result(link) }.not_to raise_error
- end
- end
-
- context 'with data-user' do
- it 'allows any User reference' do
- user = create(:user)
-
- link = reference_link(user: user.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
- result = pipeline_result(link)
-
- expect(result[:references][:user]).to eq([user])
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/relative_link_filter_spec.rb b/spec/lib/gitlab/markdown/relative_link_filter_spec.rb
deleted file mode 100644
index 027336ceb73..00000000000
--- a/spec/lib/gitlab/markdown/relative_link_filter_spec.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# encoding: UTF-8
-
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe RelativeLinkFilter do
- def filter(doc, contexts = {})
- contexts.reverse_merge!({
- commit: project.commit,
- project: project,
- project_wiki: project_wiki,
- ref: ref,
- requested_path: requested_path
- })
-
- described_class.call(doc, contexts)
- end
-
- def image(path)
- %(<img src="#{path}" />)
- end
-
- def link(path)
- %(<a href="#{path}">#{path}</a>)
- end
-
- let(:project) { create(:project) }
- let(:project_path) { project.path_with_namespace }
- let(:ref) { 'markdown' }
- let(:project_wiki) { nil }
- let(:requested_path) { '/' }
-
- shared_examples :preserve_unchanged do
- it 'does not modify any relative URL in anchor' do
- doc = filter(link('README.md'))
- expect(doc.at_css('a')['href']).to eq 'README.md'
- end
-
- it 'does not modify any relative URL in image' do
- doc = filter(image('files/images/logo-black.png'))
- expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
- end
- end
-
- shared_examples :relative_to_requested do
- it 'rebuilds URL relative to the requested path' do
- doc = filter(link('users.md'))
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/blob/#{ref}/doc/api/users.md"
- end
- end
-
- context 'with a project_wiki' do
- let(:project_wiki) { double('ProjectWiki') }
- include_examples :preserve_unchanged
- end
-
- context 'without a repository' do
- let(:project) { create(:empty_project) }
- include_examples :preserve_unchanged
- end
-
- context 'with an empty repository' do
- let(:project) { create(:project_empty_repo) }
- include_examples :preserve_unchanged
- end
-
- it 'does not raise an exception on invalid URIs' do
- act = link("://foo")
- expect { filter(act) }.not_to raise_error
- end
-
- context 'with a valid repository' do
- it 'rebuilds relative URL for a file in the repo' do
- doc = filter(link('doc/api/README.md'))
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
- end
-
- it 'rebuilds relative URL for a file in the repo up one directory' do
- relative_link = link('../api/README.md')
- doc = filter(relative_link, requested_path: 'doc/update/7.14-to-8.0.md')
-
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
- end
-
- it 'rebuilds relative URL for a file in the repo up multiple directories' do
- relative_link = link('../../../api/README.md')
- doc = filter(relative_link, requested_path: 'doc/foo/bar/baz/README.md')
-
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
- end
-
- it 'rebuilds relative URL for a file in the repo with an anchor' do
- doc = filter(link('README.md#section'))
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/blob/#{ref}/README.md#section"
- end
-
- it 'rebuilds relative URL for a directory in the repo' do
- doc = filter(link('doc/api/'))
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/tree/#{ref}/doc/api"
- end
-
- it 'rebuilds relative URL for an image in the repo' do
- doc = filter(link('files/images/logo-black.png'))
- expect(doc.at_css('a')['href']).
- to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png"
- end
-
- it 'does not modify relative URL with an anchor only' do
- doc = filter(link('#section-1'))
- expect(doc.at_css('a')['href']).to eq '#section-1'
- end
-
- it 'does not modify absolute URL' do
- doc = filter(link('http://example.com'))
- expect(doc.at_css('a')['href']).to eq 'http://example.com'
- end
-
- it 'supports Unicode filenames' do
- path = 'files/images/한글.png'
- escaped = Addressable::URI.escape(path)
-
- # Stub these methods so the file doesn't actually need to be in the repo
- allow_any_instance_of(described_class).
- to receive(:file_exists?).and_return(true)
- allow_any_instance_of(described_class).
- to receive(:image?).with(path).and_return(true)
-
- doc = filter(image(escaped))
- expect(doc.at_css('img')['src']).to match '/raw/'
- end
-
- context 'when requested path is a file in the repo' do
- let(:requested_path) { 'doc/api/README.md' }
- include_examples :relative_to_requested
- end
-
- context 'when requested path is a directory in the repo' do
- let(:requested_path) { 'doc/api' }
- include_examples :relative_to_requested
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/sanitization_filter_spec.rb b/spec/lib/gitlab/markdown/sanitization_filter_spec.rb
deleted file mode 100644
index 27cd00e8054..00000000000
--- a/spec/lib/gitlab/markdown/sanitization_filter_spec.rb
+++ /dev/null
@@ -1,199 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe SanitizationFilter do
- include FilterSpecHelper
-
- describe 'default whitelist' do
- it 'sanitizes tags that are not whitelisted' do
- act = %q{<textarea>no inputs</textarea> and <blink>no blinks</blink>}
- exp = 'no inputs and no blinks'
- expect(filter(act).to_html).to eq exp
- end
-
- it 'sanitizes tag attributes' do
- act = %q{<a href="http://example.com/bar.html" onclick="bar">Text</a>}
- exp = %q{<a href="http://example.com/bar.html">Text</a>}
- expect(filter(act).to_html).to eq exp
- end
-
- it 'sanitizes javascript in attributes' do
- act = %q(<a href="javascript:alert('foo')">Text</a>)
- exp = '<a>Text</a>'
- expect(filter(act).to_html).to eq exp
- end
-
- it 'allows whitelisted HTML tags from the user' do
- exp = act = "<dl>\n<dt>Term</dt>\n<dd>Definition</dd>\n</dl>"
- expect(filter(act).to_html).to eq exp
- end
-
- it 'sanitizes `class` attribute on any element' do
- act = %q{<strong class="foo">Strong</strong>}
- expect(filter(act).to_html).to eq %q{<strong>Strong</strong>}
- end
-
- it 'sanitizes `id` attribute on any element' do
- act = %q{<em id="foo">Emphasis</em>}
- expect(filter(act).to_html).to eq %q{<em>Emphasis</em>}
- end
- end
-
- describe 'custom whitelist' do
- it 'customizes the whitelist only once' do
- instance = described_class.new('Foo')
- 3.times { instance.whitelist }
-
- expect(instance.whitelist[:transformers].size).to eq 5
- end
-
- it 'allows syntax highlighting' do
- exp = act = %q{<pre class="code highlight white c"><code><span class="k">def</span></code></pre>}
- expect(filter(act).to_html).to eq exp
- end
-
- it 'sanitizes `class` attribute from non-highlight spans' do
- act = %q{<span class="k">def</span>}
- expect(filter(act).to_html).to eq %q{<span>def</span>}
- end
-
- it 'allows `style` attribute on table elements' do
- html = <<-HTML.strip_heredoc
- <table>
- <tr><th style="text-align: center">Head</th></tr>
- <tr><td style="text-align: right">Body</th></tr>
- </table>
- HTML
-
- doc = filter(html)
-
- expect(doc.at_css('th')['style']).to eq 'text-align: center'
- expect(doc.at_css('td')['style']).to eq 'text-align: right'
- end
-
- it 'allows `span` elements' do
- exp = act = %q{<span>Hello</span>}
- expect(filter(act).to_html).to eq exp
- end
-
- it 'removes `rel` attribute from `a` elements' do
- act = %q{<a href="#" rel="nofollow">Link</a>}
- exp = %q{<a href="#">Link</a>}
-
- expect(filter(act).to_html).to eq exp
- end
-
- # Adapted from the Sanitize test suite: http://git.io/vczrM
- protocols = {
- 'protocol-based JS injection: simple, no spaces' => {
- input: '<a href="javascript:alert(\'XSS\');">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: simple, spaces before' => {
- input: '<a href="javascript :alert(\'XSS\');">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: simple, spaces after' => {
- input: '<a href="javascript: alert(\'XSS\');">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: simple, spaces before and after' => {
- input: '<a href="javascript : alert(\'XSS\');">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: preceding colon' => {
- input: '<a href=":javascript:alert(\'XSS\');">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: UTF-8 encoding' => {
- input: '<a href="javascript&#58;">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: long UTF-8 encoding' => {
- input: '<a href="javascript&#0058;">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: long UTF-8 encoding without semicolons' => {
- input: '<a href=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: hex encoding' => {
- input: '<a href="javascript&#x3A;">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: long hex encoding' => {
- input: '<a href="javascript&#x003A;">foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: hex encoding without semicolons' => {
- input: '<a href=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>foo</a>',
- output: '<a>foo</a>'
- },
-
- 'protocol-based JS injection: null char' => {
- input: "<a href=java\0script:alert(\"XSS\")>foo</a>",
- output: '<a href="java"></a>'
- },
-
- 'protocol-based JS injection: spaces and entities' => {
- input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>',
- output: '<a href="">foo</a>'
- },
- }
-
- protocols.each do |name, data|
- it "handles #{name}" do
- doc = filter(data[:input])
-
- expect(doc.to_html).to eq data[:output]
- end
- end
-
- it 'allows non-standard anchor schemes' do
- exp = %q{<a href="irc://irc.freenode.net/git">IRC</a>}
- act = filter(exp)
-
- expect(act.to_html).to eq exp
- end
-
- it 'allows relative links' do
- exp = %q{<a href="foo/bar.md">foo/bar.md</a>}
- act = filter(exp)
-
- expect(act.to_html).to eq exp
- end
- end
-
- context 'when pipeline is :description' do
- it 'uses a stricter whitelist' do
- doc = filter('<h1>Description</h1>', pipeline: :description)
- expect(doc.to_html.strip).to eq 'Description'
- end
-
- %w(pre code img ol ul li).each do |elem|
- it "removes '#{elem}' elements" do
- act = "<#{elem}>Description</#{elem}>"
- expect(filter(act, pipeline: :description).to_html.strip).
- to eq 'Description'
- end
- end
-
- %w(b i strong em a ins del sup sub p).each do |elem|
- it "still allows '#{elem}' elements" do
- exp = act = "<#{elem}>Description</#{elem}>"
- expect(filter(act, pipeline: :description).to_html).to eq exp
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
deleted file mode 100644
index 9d9652dba46..00000000000
--- a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
+++ /dev/null
@@ -1,118 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe SnippetReferenceFilter do
- include FilterSpecHelper
-
- let(:project) { create(:empty_project, :public) }
- let(:snippet) { create(:project_snippet, project: project) }
- let(:reference) { snippet.to_reference }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Snippet #{reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'internal reference' do
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).to eq urls.
- namespace_project_snippet_url(project.namespace, project, snippet)
- end
-
- it 'links with adjacent text' do
- doc = filter("Snippet (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid snippet IDs' do
- exp = act = "Snippet #{invalidate_reference(reference)}"
-
- expect(filter(act).to_html).to eq exp
- end
-
- it 'includes a title attribute' do
- doc = filter("Snippet #{reference}")
- expect(doc.css('a').first.attr('title')).to eq "Snippet: #{snippet.title}"
- end
-
- it 'escapes the title attribute' do
- snippet.update_attribute(:title, %{"></a>whatever<a title="})
-
- doc = filter("Snippet #{reference}")
- expect(doc.text).to eq "Snippet #{reference}"
- end
-
- it 'includes default classes' do
- doc = filter("Snippet #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-snippet'
- end
-
- it 'includes a data-project attribute' do
- doc = filter("Snippet #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-project')
- expect(link.attr('data-project')).to eq project.id.to_s
- end
-
- it 'includes a data-snippet attribute' do
- doc = filter("See #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-snippet')
- expect(link.attr('data-snippet')).to eq snippet.id.to_s
- end
-
- it 'supports an :only_path context' do
- doc = filter("Snippet #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq urls.namespace_project_snippet_url(project.namespace, project, snippet, only_path: true)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Snippet #{reference}")
- expect(result[:references][:snippet]).to eq [snippet]
- end
- end
-
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:empty_project, :public, namespace: namespace) }
- let(:snippet) { create(:project_snippet, project: project2) }
- let(:reference) { snippet.to_reference(project) }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
- end
-
- it 'links with adjacent text' do
- doc = filter("See (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid snippet IDs on the referenced project' do
- exp = act = "See #{invalidate_reference(reference)}"
-
- expect(filter(act).to_html).to eq exp
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Snippet #{reference}")
- expect(result[:references][:snippet]).to eq [snippet]
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/syntax_highlight_filter_spec.rb b/spec/lib/gitlab/markdown/syntax_highlight_filter_spec.rb
deleted file mode 100644
index 6a490673728..00000000000
--- a/spec/lib/gitlab/markdown/syntax_highlight_filter_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe SyntaxHighlightFilter do
- include FilterSpecHelper
-
- it 'highlights valid code blocks' do
- result = filter('<pre><code>def fun end</code>')
- expect(result.to_html).to eq("<pre class=\"code highlight js-syntax-highlight plaintext\"><code>def fun end</code></pre>\n")
- end
-
- it 'passes through invalid code blocks' do
- allow_any_instance_of(SyntaxHighlightFilter).to receive(:block_code).and_raise(StandardError)
-
- result = filter('<pre><code>This is a test</code></pre>')
- expect(result.to_html).to eq('<pre>This is a test</pre>')
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb b/spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb
deleted file mode 100644
index ddf583a72c1..00000000000
--- a/spec/lib/gitlab/markdown/table_of_contents_filter_spec.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-# encoding: UTF-8
-
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe TableOfContentsFilter do
- include FilterSpecHelper
-
- def header(level, text)
- "<h#{level}>#{text}</h#{level}>\n"
- end
-
- it 'does nothing when :no_header_anchors is truthy' do
- exp = act = header(1, 'Header')
- expect(filter(act, no_header_anchors: 1).to_html).to eq exp
- end
-
- it 'does nothing with empty headers' do
- exp = act = header(1, nil)
- expect(filter(act).to_html).to eq exp
- end
-
- 1.upto(6) do |i|
- it "processes h#{i} elements" do
- html = header(i, "Header #{i}")
- doc = filter(html)
-
- expect(doc.css("h#{i} a").first.attr('id')).to eq "header-#{i}"
- end
- end
-
- describe 'anchor tag' do
- it 'has an `anchor` class' do
- doc = filter(header(1, 'Header'))
- expect(doc.css('h1 a').first.attr('class')).to eq 'anchor'
- end
-
- it 'links to the id' do
- doc = filter(header(1, 'Header'))
- expect(doc.css('h1 a').first.attr('href')).to eq '#header'
- end
-
- describe 'generated IDs' do
- it 'translates spaces to dashes' do
- doc = filter(header(1, 'This header has spaces in it'))
- expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-has-spaces-in-it'
- end
-
- it 'squeezes multiple spaces and dashes' do
- doc = filter(header(1, 'This---header is poorly-formatted'))
- expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-is-poorly-formatted'
- end
-
- it 'removes punctuation' do
- doc = filter(header(1, "This, header! is, filled. with @ punctuation?"))
- expect(doc.css('h1 a').first.attr('id')).to eq 'this-header-is-filled-with-punctuation'
- end
-
- it 'appends a unique number to duplicates' do
- doc = filter(header(1, 'One') + header(2, 'One'))
-
- expect(doc.css('h1 a').first.attr('id')).to eq 'one'
- expect(doc.css('h2 a').first.attr('id')).to eq 'one-1'
- end
-
- it 'supports Unicode' do
- doc = filter(header(1, '한글'))
- expect(doc.css('h1 a').first.attr('id')).to eq '한글'
- expect(doc.css('h1 a').first.attr('href')).to eq '#한글'
- end
- end
- end
-
- describe 'result' do
- def result(html)
- HTML::Pipeline.new([described_class]).call(html)
- end
-
- let(:results) { result(header(1, 'Header 1') + header(2, 'Header 2')) }
- let(:doc) { Nokogiri::XML::DocumentFragment.parse(results[:toc]) }
-
- it 'is contained within a `ul` element' do
- expect(doc.children.first.name).to eq 'ul'
- expect(doc.children.first.attr('class')).to eq 'section-nav'
- end
-
- it 'contains an `li` element for each header' do
- expect(doc.css('li').length).to eq 2
-
- links = doc.css('li a')
-
- expect(links.first.attr('href')).to eq '#header-1'
- expect(links.first.text).to eq 'Header 1'
- expect(links.last.attr('href')).to eq '#header-2'
- expect(links.last.text).to eq 'Header 2'
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/task_list_filter_spec.rb b/spec/lib/gitlab/markdown/task_list_filter_spec.rb
deleted file mode 100644
index 94f39cc966e..00000000000
--- a/spec/lib/gitlab/markdown/task_list_filter_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe TaskListFilter do
- include FilterSpecHelper
-
- it 'does not apply `task-list` class to non-task lists' do
- exp = act = %(<ul><li>Item</li></ul>)
- expect(filter(act).to_html).to eq exp
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/upload_link_filter_spec.rb b/spec/lib/gitlab/markdown/upload_link_filter_spec.rb
deleted file mode 100644
index 9ae45a6f559..00000000000
--- a/spec/lib/gitlab/markdown/upload_link_filter_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# encoding: UTF-8
-
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe UploadLinkFilter do
- def filter(doc, contexts = {})
- contexts.reverse_merge!({
- project: project
- })
-
- described_class.call(doc, contexts)
- end
-
- def image(path)
- %(<img src="#{path}" />)
- end
-
- def link(path)
- %(<a href="#{path}">#{path}</a>)
- end
-
- let(:project) { create(:project) }
-
- shared_examples :preserve_unchanged do
- it 'does not modify any relative URL in anchor' do
- doc = filter(link('README.md'))
- expect(doc.at_css('a')['href']).to eq 'README.md'
- end
-
- it 'does not modify any relative URL in image' do
- doc = filter(image('files/images/logo-black.png'))
- expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
- end
- end
-
- it 'does not raise an exception on invalid URIs' do
- act = link("://foo")
- expect { filter(act) }.not_to raise_error
- end
-
- context 'with a valid repository' do
- it 'rebuilds relative URL for a link' do
- doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href']).
- to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
- end
-
- it 'rebuilds relative URL for an image' do
- doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href']).
- to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
- end
-
- it 'does not modify absolute URL' do
- doc = filter(link('http://example.com'))
- expect(doc.at_css('a')['href']).to eq 'http://example.com'
- end
-
- it 'supports Unicode filenames' do
- path = '/uploads/한글.png'
- escaped = Addressable::URI.escape(path)
-
- # Stub these methods so the file doesn't actually need to be in the repo
- allow_any_instance_of(described_class).
- to receive(:file_exists?).and_return(true)
- allow_any_instance_of(described_class).
- to receive(:image?).with(path).and_return(true)
-
- doc = filter(image(escaped))
- expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
deleted file mode 100644
index d9e0d7c42db..00000000000
--- a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
+++ /dev/null
@@ -1,122 +0,0 @@
-require 'spec_helper'
-
-module Gitlab::Markdown
- describe UserReferenceFilter do
- include FilterSpecHelper
-
- let(:project) { create(:empty_project, :public) }
- let(:user) { create(:user) }
- let(:reference) { user.to_reference }
-
- it 'requires project context' do
- expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
- end
-
- it 'ignores invalid users' do
- exp = act = "Hey #{invalidate_reference(reference)}"
- expect(filter(act).to_html).to eq(exp)
- end
-
- %w(pre code a style).each do |elem|
- it "ignores valid references contained inside '#{elem}' element" do
- exp = act = "<#{elem}>Hey #{reference}</#{elem}>"
- expect(filter(act).to_html).to eq exp
- end
- end
-
- context 'mentioning @all' do
- let(:reference) { User.reference_prefix + 'all' }
-
- before do
- project.team << [project.creator, :developer]
- end
-
- it 'supports a special @all mention' do
- doc = filter("Hey #{reference}")
- expect(doc.css('a').length).to eq 1
- expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_url(project.namespace, project)
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}")
- expect(result[:references][:user]).to eq [project.creator]
- end
- end
-
- context 'mentioning a user' do
- it 'links to a User' do
- doc = filter("Hey #{reference}")
- expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
- end
-
- it 'links to a User with a period' do
- user = create(:user, name: 'alphA.Beta')
-
- doc = filter("Hey #{user.to_reference}")
- expect(doc.css('a').length).to eq 1
- end
-
- it 'links to a User with an underscore' do
- user = create(:user, name: 'ping_pong_king')
-
- doc = filter("Hey #{user.to_reference}")
- expect(doc.css('a').length).to eq 1
- end
-
- it 'includes a data-user attribute' do
- doc = filter("Hey #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-user')
- expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}")
- expect(result[:references][:user]).to eq [user]
- end
- end
-
- context 'mentioning a group' do
- let(:group) { create(:group) }
- let(:reference) { group.to_reference }
-
- it 'links to the Group' do
- doc = filter("Hey #{reference}")
- expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
- end
-
- it 'includes a data-group attribute' do
- doc = filter("Hey #{reference}")
- link = doc.css('a').first
-
- expect(link).to have_attribute('data-group')
- expect(link.attr('data-group')).to eq group.id.to_s
- end
-
- it 'adds to the results hash' do
- result = reference_pipeline_result("Hey #{reference}")
- expect(result[:references][:user]).to eq group.users
- end
- end
-
- it 'links with adjacent text' do
- doc = filter("Mention me (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
- end
-
- it 'includes default classes' do
- doc = filter("Hey #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project_member'
- end
-
- it 'supports an :only_path context' do
- doc = filter("Hey #{reference}", only_path: true)
- link = doc.css('a').first.attr('href')
-
- expect(link).not_to match %r(https?://)
- expect(link).to eq urls.user_path(user)
- end
- end
-end
diff --git a/spec/lib/gitlab/markup_helper_spec.rb b/spec/lib/gitlab/markup_helper_spec.rb
index e610fab05da..93b91b849f2 100644
--- a/spec/lib/gitlab/markup_helper_spec.rb
+++ b/spec/lib/gitlab/markup_helper_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::MarkupHelper do
+describe Gitlab::MarkupHelper, lib: true do
describe '#markup?' do
%w(textile rdoc org creole wiki
mediawiki rst adoc ad asciidoc mdown md markdown).each do |type|
diff --git a/spec/lib/gitlab/note_data_builder_spec.rb b/spec/lib/gitlab/note_data_builder_spec.rb
index 448cd0c6880..6cbdae737f4 100644
--- a/spec/lib/gitlab/note_data_builder_spec.rb
+++ b/spec/lib/gitlab/note_data_builder_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::NoteDataBuilder' do
+describe 'Gitlab::NoteDataBuilder', lib: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:data) { Gitlab::NoteDataBuilder.build(note, user) }
diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
index 5632f2306ec..8aaeb5779d3 100644
--- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb
+++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::OAuth::AuthHash do
+describe Gitlab::OAuth::AuthHash, lib: true do
let(:auth_hash) do
Gitlab::OAuth::AuthHash.new(
OmniAuth::AuthHash.new(
@@ -14,7 +14,7 @@ describe Gitlab::OAuth::AuthHash do
let(:uid_raw) do
"CN=Onur K\xC3\xBC\xC3\xA7\xC3\xBCk,OU=Test,DC=example,DC=net"
end
- let(:email_raw) { "onur.k\xC3\xBC\xC3\xA7\xC3\xBCk@example.net" }
+ let(:email_raw) { "onur.k\xC3\xBC\xC3\xA7\xC3\xBCk_ABC-123@example.net" }
let(:nickname_raw) { "ok\xC3\xBC\xC3\xA7\xC3\xBCk" }
let(:first_name_raw) { 'Onur' }
let(:last_name_raw) { "K\xC3\xBC\xC3\xA7\xC3\xBCk" }
@@ -66,7 +66,7 @@ describe Gitlab::OAuth::AuthHash do
before { info_hash.delete(:nickname) }
it 'takes the first part of the email as username' do
- expect(auth_hash.username).to eql 'onur-kucuk'
+ expect(auth_hash.username).to eql 'onur.kucuk_ABC-123'
end
end
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index fd3ab1fb7c8..925bc442a90 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::OAuth::User do
+describe Gitlab::OAuth::User, lib: true do
let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) }
let(:gl_user) { oauth_user.gl_user }
let(:uid) { 'my-uid' }
diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb
index e53efec6c67..795cf241278 100644
--- a/spec/lib/gitlab/popen_spec.rb
+++ b/spec/lib/gitlab/popen_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::Popen', no_db: true do
+describe 'Gitlab::Popen', lib: true, no_db: true do
let(:path) { Rails.root.join('tmp').to_s }
before do
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 19327ac8ce0..efc2e5f4ef1 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ProjectSearchResults do
+describe Gitlab::ProjectSearchResults, lib: true do
let(:project) { create(:project) }
let(:query) { 'hello world' }
diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb
index 02710742625..3ef61685398 100644
--- a/spec/lib/gitlab/push_data_builder_spec.rb
+++ b/spec/lib/gitlab/push_data_builder_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::PushDataBuilder' do
+describe 'Gitlab::PushDataBuilder', lib: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
@@ -17,9 +17,9 @@ describe 'Gitlab::PushDataBuilder' do
it { expect(data[:repository][:git_ssh_url]).to eq(project.ssh_url_to_repo) }
it { expect(data[:repository][:visibility_level]).to eq(project.visibility_level) }
it { expect(data[:total_commits_count]).to eq(3) }
- it { expect(data[:added]).to eq(["gitlab-grack"]) }
- it { expect(data[:modified]).to eq([".gitmodules", "files/ruby/popen.rb", "files/ruby/regex.rb"]) }
- it { expect(data[:removed]).to eq([]) }
+ it { expect(data[:commits].first[:added]).to eq(["gitlab-grack"]) }
+ it { expect(data[:commits].first[:modified]).to eq([".gitmodules"]) }
+ it { expect(data[:commits].first[:removed]).to eq([]) }
end
describe :build do
@@ -38,8 +38,5 @@ describe 'Gitlab::PushDataBuilder' do
it { expect(data[:ref]).to eq('refs/tags/v1.1.0') }
it { expect(data[:commits]).to be_empty }
it { expect(data[:total_commits_count]).to be_zero }
- it { expect(data[:added]).to eq([]) }
- it { expect(data[:modified]).to eq([]) }
- it { expect(data[:removed]).to eq([]) }
end
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index ad84d2274e8..66dc5d4911d 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ReferenceExtractor do
+describe Gitlab::ReferenceExtractor, lib: true do
let(:project) { create(:project) }
subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 7fdc8fa600d..d67ee423b9b 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -1,7 +1,7 @@
# coding: utf-8
require 'spec_helper'
-describe Gitlab::Regex do
+describe Gitlab::Regex, lib: true do
describe 'project path regex' do
it { expect('gitlab-ce').to match(Gitlab::Regex.project_path_regex) }
it { expect('gitlab_git').to match(Gitlab::Regex.project_path_regex) }
diff --git a/spec/lib/gitlab/sherlock/collection_spec.rb b/spec/lib/gitlab/sherlock/collection_spec.rb
index a8a9d6fc7bc..de6bb86c5dd 100644
--- a/spec/lib/gitlab/sherlock/collection_spec.rb
+++ b/spec/lib/gitlab/sherlock/collection_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Collection do
+describe Gitlab::Sherlock::Collection, lib: true do
let(:collection) { described_class.new }
let(:transaction) do
diff --git a/spec/lib/gitlab/sherlock/file_sample_spec.rb b/spec/lib/gitlab/sherlock/file_sample_spec.rb
index f05a59f56f6..cadf8bbce78 100644
--- a/spec/lib/gitlab/sherlock/file_sample_spec.rb
+++ b/spec/lib/gitlab/sherlock/file_sample_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::FileSample do
+describe Gitlab::Sherlock::FileSample, lib: true do
let(:sample) { described_class.new(__FILE__, [], 150.4, 2) }
describe '#id' do
diff --git a/spec/lib/gitlab/sherlock/line_profiler_spec.rb b/spec/lib/gitlab/sherlock/line_profiler_spec.rb
index 8f2e1299714..d57627bba2b 100644
--- a/spec/lib/gitlab/sherlock/line_profiler_spec.rb
+++ b/spec/lib/gitlab/sherlock/line_profiler_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::LineProfiler do
+describe Gitlab::Sherlock::LineProfiler, lib: true do
let(:profiler) { described_class.new }
describe '#profile' do
diff --git a/spec/lib/gitlab/sherlock/line_sample_spec.rb b/spec/lib/gitlab/sherlock/line_sample_spec.rb
index 5f02f6a3213..f9b61f8684e 100644
--- a/spec/lib/gitlab/sherlock/line_sample_spec.rb
+++ b/spec/lib/gitlab/sherlock/line_sample_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::LineSample do
+describe Gitlab::Sherlock::LineSample, lib: true do
let(:sample) { described_class.new(150.0, 4) }
describe '#duration' do
diff --git a/spec/lib/gitlab/sherlock/location_spec.rb b/spec/lib/gitlab/sherlock/location_spec.rb
index b295a624b35..5739afa6b1e 100644
--- a/spec/lib/gitlab/sherlock/location_spec.rb
+++ b/spec/lib/gitlab/sherlock/location_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Location do
+describe Gitlab::Sherlock::Location, lib: true do
let(:location) { described_class.new(__FILE__, 1) }
describe 'from_ruby_location' do
diff --git a/spec/lib/gitlab/sherlock/middleware_spec.rb b/spec/lib/gitlab/sherlock/middleware_spec.rb
index aa74fc53a79..2bbeb25ce98 100644
--- a/spec/lib/gitlab/sherlock/middleware_spec.rb
+++ b/spec/lib/gitlab/sherlock/middleware_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Middleware do
+describe Gitlab::Sherlock::Middleware, lib: true do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
diff --git a/spec/lib/gitlab/sherlock/query_spec.rb b/spec/lib/gitlab/sherlock/query_spec.rb
index a9afef5dc1d..05da915ccfd 100644
--- a/spec/lib/gitlab/sherlock/query_spec.rb
+++ b/spec/lib/gitlab/sherlock/query_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Query do
+describe Gitlab::Sherlock::Query, lib: true do
let(:started_at) { Time.utc(2015, 1, 1) }
let(:finished_at) { started_at + 5 }
diff --git a/spec/lib/gitlab/sherlock/transaction_spec.rb b/spec/lib/gitlab/sherlock/transaction_spec.rb
index bb49fb65cf8..7553f2a045f 100644
--- a/spec/lib/gitlab/sherlock/transaction_spec.rb
+++ b/spec/lib/gitlab/sherlock/transaction_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Sherlock::Transaction do
+describe Gitlab::Sherlock::Transaction, lib: true do
let(:transaction) { described_class.new('POST', '/cat_pictures') }
describe '#id' do
@@ -84,6 +84,19 @@ describe Gitlab::Sherlock::Transaction do
end
end
+ describe '#query_duration' do
+ it 'returns the total query duration in seconds' do
+ time = Time.now
+ query1 = Gitlab::Sherlock::Query.new('SELECT 1', time, time + 5)
+ query2 = Gitlab::Sherlock::Query.new('SELECT 2', time, time + 2)
+
+ transaction.queries << query1
+ transaction.queries << query2
+
+ expect(transaction.query_duration).to be_within(0.1).of(7.0)
+ end
+ end
+
describe '#to_param' do
it 'returns the transaction ID' do
expect(transaction.to_param).to eq(transaction.id)
diff --git a/spec/lib/gitlab/sql/union_spec.rb b/spec/lib/gitlab/sql/union_spec.rb
index 9e1cd4419e0..0cdbab87544 100644
--- a/spec/lib/gitlab/sql/union_spec.rb
+++ b/spec/lib/gitlab/sql/union_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::SQL::Union do
+describe Gitlab::SQL::Union, lib: true do
describe '#to_sql' do
it 'returns a String joining relations together using a UNION' do
rel1 = User.where(email: 'alice@example.com')
diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb
index e554458e41c..7a140518dd2 100644
--- a/spec/lib/gitlab/themes_spec.rb
+++ b/spec/lib/gitlab/themes_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Themes do
+describe Gitlab::Themes, lib: true do
describe '.body_classes' do
it 'returns a space-separated list of class names' do
css = described_class.body_classes
diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb
index 8df84665e16..e958e087a80 100644
--- a/spec/lib/gitlab/upgrader_spec.rb
+++ b/spec/lib/gitlab/upgrader_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Upgrader do
+describe Gitlab::Upgrader, lib: true do
let(:upgrader) { Gitlab::Upgrader.new }
let(:current_version) { Gitlab::VERSION }
diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb
index 260364a513e..4092f7fb638 100644
--- a/spec/lib/gitlab/uploads_transfer_spec.rb
+++ b/spec/lib/gitlab/uploads_transfer_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::UploadsTransfer do
+describe Gitlab::UploadsTransfer, lib: true do
before do
@root_dir = File.join(Rails.root, "public", "uploads")
@upload_transfer = Gitlab::UploadsTransfer.new
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index 5153ed15af3..f023be6ae45 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::UrlBuilder do
+describe Gitlab::UrlBuilder, lib: true do
describe 'When asking for an issue' do
it 'returns the issue url' do
issue = create(:issue)
diff --git a/spec/lib/gitlab/version_info_spec.rb b/spec/lib/gitlab/version_info_spec.rb
index 18f71b40fe0..706ee9bec58 100644
--- a/spec/lib/gitlab/version_info_spec.rb
+++ b/spec/lib/gitlab/version_info_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Gitlab::VersionInfo', no_db: true do
+describe 'Gitlab::VersionInfo', lib: true, no_db: true do
before do
@unknown = Gitlab::VersionInfo.new
@v0_0_1 = Gitlab::VersionInfo.new(0, 0, 1)
diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb
index 37240d51310..63b5292b098 100644
--- a/spec/lib/repository_cache_spec.rb
+++ b/spec/lib/repository_cache_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../lib/repository_cache'
-describe RepositoryCache do
+describe RepositoryCache, lib: true do
let(:backend) { double('backend').as_null_object }
let(:cache) { RepositoryCache.new('example', backend) }
diff --git a/spec/mailers/ci/notify_spec.rb b/spec/mailers/ci/notify_spec.rb
deleted file mode 100644
index b83fb41603b..00000000000
--- a/spec/mailers/ci/notify_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper'
-
-describe Ci::Notify do
- include EmailSpec::Helpers
- include EmailSpec::Matchers
-
- before do
- @commit = FactoryGirl.create :ci_commit
- @build = FactoryGirl.create :ci_build, commit: @commit
- end
-
- describe 'build success' do
- subject { Ci::Notify.build_success_email(@build.id, 'wow@example.com') }
-
- it 'has the correct subject' do
- should have_subject /Build success for/
- end
-
- it 'contains name of project' do
- should have_body_text /build successful/
- end
- end
-
- describe 'build fail' do
- subject { Ci::Notify.build_fail_email(@build.id, 'wow@example.com') }
-
- it 'has the correct subject' do
- should have_subject /Build failed for/
- end
-
- it 'contains name of project' do
- should have_body_text /build failed/
- end
- end
-end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 47863d54579..154901a2fbc 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -13,6 +13,7 @@ describe Notify do
let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to }
let(:recipient) { create(:user, email: 'recipient@example.com') }
let(:project) { create(:project) }
+ let(:build) { create(:ci_build) }
before(:each) do
ActionMailer::Base.deliveries.clear
@@ -77,6 +78,32 @@ describe Notify do
end
end
+ shared_examples 'it should have Gmail Actions links' do
+ it { is_expected.to have_body_text /ViewAction/ }
+ end
+
+ shared_examples 'it should not have Gmail Actions links' do
+ it { is_expected.to_not have_body_text /ViewAction/ }
+ end
+
+ shared_examples 'it should show Gmail Actions View Issue link' do
+ it_behaves_like 'it should have Gmail Actions links'
+
+ it { is_expected.to have_body_text /View Issue/ }
+ end
+
+ shared_examples 'it should show Gmail Actions View Merge request link' do
+ it_behaves_like 'it should have Gmail Actions links'
+
+ it { is_expected.to have_body_text /View Merge request/ }
+ end
+
+ shared_examples 'it should show Gmail Actions View Commit link' do
+ it_behaves_like 'it should have Gmail Actions links'
+
+ it { is_expected.to have_body_text /View Commit/ }
+ end
+
describe 'for new users, the email' do
let(:example_site_path) { root_path }
let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) }
@@ -87,6 +114,7 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'a new user email', new_user_address
+ it_behaves_like 'it should not have Gmail Actions links'
it 'contains the password text' do
is_expected.to have_body_text /Click here to set your password/
@@ -115,6 +143,7 @@ describe Notify do
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'a new user email', new_user_address
+ it_behaves_like 'it should not have Gmail Actions links'
it 'should not contain the new user\'s password' do
is_expected.not_to have_body_text /password/
@@ -127,6 +156,7 @@ describe Notify do
subject { Notify.new_ssh_key_email(key.id) }
it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
it 'is sent to the new user' do
is_expected.to deliver_to key.user.email
@@ -150,6 +180,8 @@ describe Notify do
subject { Notify.new_email_email(email.id) }
+ it_behaves_like 'it should not have Gmail Actions links'
+
it 'is sent to the new user' do
is_expected.to deliver_to email.user.email
end
@@ -194,6 +226,7 @@ describe Notify do
it_behaves_like 'an assignee email'
it_behaves_like 'an email starting a new thread', 'issue'
+ it_behaves_like 'it should show Gmail Actions View Issue link'
it 'has the correct subject' do
is_expected.to have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/
@@ -207,16 +240,19 @@ describe Notify do
describe 'that are new with a description' do
subject { Notify.new_issue_email(issue_with_description.assignee_id, issue_with_description.id) }
+ it_behaves_like 'it should show Gmail Actions View Issue link'
+
it 'contains the description' do
is_expected.to have_body_text /#{issue_with_description.description}/
end
end
describe 'that have been reassigned' do
- subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user) }
+ subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread', 'issue'
+ it_behaves_like 'it should show Gmail Actions View Issue link'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -243,9 +279,10 @@ describe Notify do
describe 'status changed' do
let(:status) { 'closed' }
- subject { Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) }
+ subject { Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) }
it_behaves_like 'an answer to an existing thread', 'issue'
+ it_behaves_like 'it should show Gmail Actions View Issue link'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -269,7 +306,6 @@ describe Notify do
is_expected.to have_body_text /#{namespace_project_issue_path project.namespace, project, issue}/
end
end
-
end
context 'for merge requests' do
@@ -282,6 +318,7 @@ describe Notify do
it_behaves_like 'an assignee email'
it_behaves_like 'an email starting a new thread', 'merge_request'
+ it_behaves_like 'it should show Gmail Actions View Merge request link'
it 'has the correct subject' do
is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
@@ -307,6 +344,8 @@ describe Notify do
describe 'that are new with a description' do
subject { Notify.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) }
+ it_behaves_like 'it should show Gmail Actions View Merge request link'
+
it 'contains the description' do
is_expected.to have_body_text /#{merge_request_with_description.description}/
end
@@ -317,6 +356,7 @@ describe Notify do
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread', 'merge_request'
+ it_behaves_like 'it should show Gmail Actions View Merge request link'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -343,9 +383,10 @@ describe Notify do
describe 'status changed' do
let(:status) { 'reopened' }
- subject { Notify.merge_request_status_email(recipient.id, merge_request.id, status, current_user) }
+ subject { Notify.merge_request_status_email(recipient.id, merge_request.id, status, current_user.id) }
it_behaves_like 'an answer to an existing thread', 'merge_request'
+ it_behaves_like 'it should show Gmail Actions View Merge request link'
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
@@ -375,6 +416,7 @@ describe Notify do
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread', 'merge_request'
+ it_behaves_like 'it should show Gmail Actions View Merge request link'
it 'is sent as the merge author' do
sender = subject.header[:from].addrs[0]
@@ -403,6 +445,7 @@ describe Notify do
subject { Notify.project_was_moved_email(project.id, user.id, "gitlab/gitlab") }
it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
it 'has the correct subject' do
is_expected.to have_subject /Project was moved/
@@ -424,13 +467,16 @@ describe Notify do
subject { Notify.project_access_granted_email(project_member.id) }
it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
it 'has the correct subject' do
is_expected.to have_subject /Access to project was granted/
end
+
it 'contains name of project' do
is_expected.to have_body_text /#{project.name}/
end
+
it 'contains new user role' do
is_expected.to have_body_text /#{project_member.human_access}/
end
@@ -445,6 +491,8 @@ describe Notify do
end
shared_examples 'a note email' do
+ it_behaves_like 'it should have Gmail Actions links'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(note_author.name)
@@ -469,6 +517,7 @@ describe Notify do
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread', 'commit'
+ it_behaves_like 'it should show Gmail Actions View Commit link'
it 'has the correct subject' do
is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/
@@ -488,6 +537,7 @@ describe Notify do
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread', 'merge_request'
+ it_behaves_like 'it should show Gmail Actions View Merge request link'
it 'has the correct subject' do
is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
@@ -507,6 +557,7 @@ describe Notify do
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread', 'issue'
+ it_behaves_like 'it should show Gmail Actions View Issue link'
it 'has the correct subject' do
is_expected.to have_subject /#{issue.title} \(##{issue.iid}\)/
@@ -527,6 +578,7 @@ describe Notify do
subject { Notify.group_access_granted_email(membership.id) }
it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
it 'has the correct subject' do
is_expected.to have_subject /Access to group was granted/
@@ -546,8 +598,10 @@ describe Notify do
let(:user) { create(:user, email: 'old-email@mail.com') }
before do
- user.email = "new-email@mail.com"
- user.save
+ perform_enqueued_jobs do
+ user.email = "new-email@mail.com"
+ user.save
+ end
end
subject { ActionMailer::Base.deliveries.last }
@@ -574,6 +628,8 @@ describe Notify do
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :create) }
+ it_behaves_like 'it should not have Gmail Actions links'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(user.name)
@@ -600,6 +656,8 @@ describe Notify do
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :create) }
+ it_behaves_like 'it should not have Gmail Actions links'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(user.name)
@@ -625,6 +683,8 @@ describe Notify do
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :delete) }
+ it_behaves_like 'it should not have Gmail Actions links'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(user.name)
@@ -646,6 +706,8 @@ describe Notify do
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) }
+ it_behaves_like 'it should not have Gmail Actions links'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(user.name)
@@ -671,6 +733,8 @@ describe Notify do
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, send_from_committer_email: send_from_committer_email) }
+ it_behaves_like 'it should not have Gmail Actions links'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(user.name)
@@ -774,6 +838,8 @@ describe Notify do
subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare) }
+ it_behaves_like 'it should show Gmail Actions View Commit link'
+
it 'is sent as the author' do
sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq(user.name)
@@ -800,4 +866,32 @@ describe Notify do
is_expected.to have_body_text /#{diff_path}/
end
end
+
+ describe 'build success' do
+ before { build.success }
+
+ subject { Notify.build_success_email(build.id, 'wow@example.com') }
+
+ it 'has the correct subject' do
+ should have_subject /Build success for/
+ end
+
+ it 'contains name of project' do
+ should have_body_text build.project_name
+ end
+ end
+
+ describe 'build fail' do
+ before { build.drop }
+
+ subject { Notify.build_fail_email(build.id, 'wow@example.com') }
+
+ it 'has the correct subject' do
+ should have_subject /Build failed for/
+ end
+
+ it 'contains name of project' do
+ should have_body_text build.project_name
+ end
+ end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index dfbac7b4004..5f64453a35f 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -36,6 +36,22 @@ describe ApplicationSetting, models: true do
it { expect(setting).to be_valid }
+ describe 'validations' do
+ let(:http) { 'http://example.com' }
+ let(:https) { 'https://example.com' }
+ let(:ftp) { 'ftp://example.com' }
+
+ it { is_expected.to allow_value(nil).for(:home_page_url) }
+ it { is_expected.to allow_value(http).for(:home_page_url) }
+ it { is_expected.to allow_value(https).for(:home_page_url) }
+ it { is_expected.not_to allow_value(ftp).for(:home_page_url) }
+
+ it { is_expected.to allow_value(nil).for(:after_sign_out_path) }
+ it { is_expected.to allow_value(http).for(:after_sign_out_path) }
+ it { is_expected.to allow_value(https).for(:after_sign_out_path) }
+ it { is_expected.not_to allow_value(ftp).for(:after_sign_out_path) }
+ end
+
context 'restricted signup domains' do
it 'set single domain' do
setting.restricted_signup_domains_raw = 'example.com'
@@ -57,26 +73,4 @@ describe ApplicationSetting, models: true do
expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com'])
end
end
-
- context 'shared runners' do
- let(:gl_project) { create(:empty_project) }
-
- before do
- allow_any_instance_of(Project).to receive(:current_application_settings).and_return(setting)
- end
-
- subject { gl_project.ensure_gitlab_ci_project.shared_runners_enabled }
-
- context 'enabled' do
- before { setting.update_attributes(shared_runners_enabled: true) }
-
- it { is_expected.to be_truthy }
- end
-
- context 'disabled' do
- before { setting.update_attributes(shared_runners_enabled: false) }
-
- it { is_expected.to be_falsey }
- end
- end
end
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index d80748f23a4..e4cac105110 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -15,11 +15,26 @@
require 'spec_helper'
-describe BroadcastMessage do
+describe BroadcastMessage, models: true do
subject { create(:broadcast_message) }
it { is_expected.to be_valid }
+ describe 'validations' do
+ let(:triplet) { '#000' }
+ let(:hex) { '#AABBCC' }
+
+ it { is_expected.to allow_value(nil).for(:color) }
+ it { is_expected.to allow_value(triplet).for(:color) }
+ it { is_expected.to allow_value(hex).for(:color) }
+ it { is_expected.not_to allow_value('000').for(:color) }
+
+ it { is_expected.to allow_value(nil).for(:font) }
+ it { is_expected.to allow_value(triplet).for(:font) }
+ it { is_expected.to allow_value(hex).for(:font) }
+ it { is_expected.not_to allow_value('000').for(:font) }
+ end
+
describe :current do
it "should return last message if time match" do
broadcast_message = create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow)
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 839b4c6b16e..96b6f1dbca6 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -25,10 +25,9 @@
require 'spec_helper'
-describe Ci::Build do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+describe Ci::Build, models: true do
+ let(:project) { FactoryGirl.create :empty_project }
+ let(:commit) { FactoryGirl.create :ci_commit, project: project }
let(:build) { FactoryGirl.create :ci_build, commit: commit }
it { is_expected.to validate_presence_of :ref }
@@ -112,7 +111,7 @@ describe Ci::Build do
let(:token) { 'my_secret_token' }
before do
- build.project.update_attributes(token: token)
+ build.project.update_attributes(runners_token: token)
build.update_attributes(trace: token)
end
@@ -120,11 +119,12 @@ describe Ci::Build do
end
end
- describe :timeout do
- subject { build.timeout }
-
- it { is_expected.to eq(commit.project.timeout) }
- end
+ # TODO: build timeout
+ # describe :timeout do
+ # subject { build.timeout }
+ #
+ # it { is_expected.to eq(commit.project.timeout) }
+ # end
describe :options do
let(:options) do
@@ -140,11 +140,12 @@ describe Ci::Build do
it { is_expected.to eq(options) }
end
- describe :allow_git_fetch do
- subject { build.allow_git_fetch }
-
- it { is_expected.to eq(project.allow_git_fetch) }
- end
+ # TODO: allow_git_fetch
+ # describe :allow_git_fetch do
+ # subject { build.allow_git_fetch }
+ #
+ # it { is_expected.to eq(project.allow_git_fetch) }
+ # end
describe :project do
subject { build.project }
@@ -164,12 +165,6 @@ describe Ci::Build do
it { is_expected.to eq(project.name) }
end
- describe :repo_url do
- subject { build.repo_url }
-
- it { is_expected.to eq(project.repo_url_with_auth) }
- end
-
describe :extract_coverage do
context 'valid content & regex' do
subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', '\(\d+.\d+\%\) covered') }
@@ -266,40 +261,6 @@ describe Ci::Build do
end
end
- describe :project_recipients do
- let(:pusher_email) { 'pusher@gitlab.test' }
- let(:user) { User.new(notification_email: pusher_email) }
- subject { build.project_recipients }
-
- before do
- build.update_attributes(user: user)
- end
-
- it 'should return pusher_email as only recipient when no additional recipients are given' do
- project.update_attributes(email_add_pusher: true,
- email_recipients: '')
- is_expected.to eq([pusher_email])
- end
-
- it 'should return pusher_email and additional recipients' do
- project.update_attributes(email_add_pusher: true,
- email_recipients: 'rec1 rec2')
- is_expected.to eq(['rec1', 'rec2', pusher_email])
- end
-
- it 'should return recipients' do
- project.update_attributes(email_add_pusher: false,
- email_recipients: 'rec1 rec2')
- is_expected.to eq(['rec1', 'rec2'])
- end
-
- it 'should return unique recipients only' do
- project.update_attributes(email_add_pusher: true,
- email_recipients: "rec1 rec1 #{pusher_email}")
- is_expected.to eq(['rec1', pusher_email])
- end
- end
-
describe :can_be_served? do
let(:runner) { FactoryGirl.create :ci_specific_runner }
@@ -415,4 +376,18 @@ describe Ci::Build do
is_expected.to_not be_nil
end
end
+
+ describe :repo_url do
+ let(:build) { FactoryGirl.create :ci_build }
+ let(:project) { build.project }
+
+ subject { build.repo_url }
+
+ it { is_expected.to be_a(String) }
+ it { is_expected.to end_with(".git") }
+ it { is_expected.to start_with(project.web_url[0..6]) }
+ it { is_expected.to include(build.token) }
+ it { is_expected.to include('gitlab-ci-token') }
+ it { is_expected.to include(project.web_url[7..-1]) }
+ end
end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index a13f6458cac..b193e16e7f8 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -13,17 +13,16 @@
# tag :boolean default(FALSE)
# yaml_errors :text
# committed_at :datetime
-# gl_project_id :integer
+# project_id :integer
#
require 'spec_helper'
-describe Ci::Commit do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+describe Ci::Commit, models: true do
+ let(:project) { FactoryGirl.create :empty_project }
+ let(:commit) { FactoryGirl.create :ci_commit, project: project }
- it { is_expected.to belong_to(:gl_project) }
+ it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:statuses) }
it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:builds) }
@@ -37,16 +36,16 @@ describe Ci::Commit do
let(:project) { FactoryGirl.create :empty_project }
it 'returns ordered list of commits' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
+ commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit1])
end
it 'returns commits ordered by committed_at and id, with nulls last' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
- commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
- commit4 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
+ commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
+ commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hours.ago, project: project
+ commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
end
end
@@ -162,7 +161,7 @@ describe Ci::Commit do
end
describe :create_builds do
- let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let!(:commit) { FactoryGirl.create :ci_commit, project: project }
def create_builds(trigger_request = nil)
commit.create_builds('master', false, nil, trigger_request)
@@ -390,9 +389,8 @@ describe Ci::Commit do
end
describe "coverage" do
- let(:project) { FactoryGirl.create :ci_project, coverage_regex: "/.*/" }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" }
+ let(:commit) { FactoryGirl.create :ci_commit, project: project }
it "calculates average when there are two builds with coverage" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit
diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb
deleted file mode 100644
index e23d6ae2c28..00000000000
--- a/spec/models/ci/project_services/hip_chat_message_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'spec_helper'
-
-describe Ci::HipChatMessage do
- subject { Ci::HipChatMessage.new(build) }
-
- let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
-
- let(:build) do
- commit.builds.first
- end
-
- context 'when all matrix builds succeed' do
- it 'returns a successful message' do
- commit.create_builds('master', false, nil)
- commit.builds.update_all(status: "success")
- commit.reload
-
- expect(subject.status_color).to eq 'green'
- expect(subject.notify?).to be_falsey
- expect(subject.to_s).to match(/Commit #\d+/)
- expect(subject.to_s).to match(/Successful in \d+ second\(s\)\./)
- end
- end
-
- context 'when at least one matrix build fails' do
- it 'returns a failure message' do
- commit.create_builds('master', false, nil)
- first_build = commit.builds.first
- second_build = commit.builds.last
- first_build.update(status: "success")
- second_build.update(status: "failed")
-
- expect(subject.status_color).to eq 'red'
- expect(subject.notify?).to be_truthy
- expect(subject.to_s).to match(/Commit #\d+/)
- expect(subject.to_s).to match(/Failed in \d+ second\(s\)\./)
- end
- end
-end
diff --git a/spec/models/ci/project_services/hip_chat_service_spec.rb b/spec/models/ci/project_services/hip_chat_service_spec.rb
deleted file mode 100644
index d9ccc855edf..00000000000
--- a/spec/models/ci/project_services/hip_chat_service_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-
-require 'spec_helper'
-
-describe Ci::HipChatService do
-
- describe "Validations" do
-
- context "active" do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of :hipchat_room }
- it { is_expected.to validate_presence_of :hipchat_token }
-
- end
- end
-
- describe "Execute" do
-
- let(:service) { Ci::HipChatService.new }
- let(:commit) { FactoryGirl.create :ci_commit }
- let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
- let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' }
-
- before do
- allow(service).to receive_messages(
- project: commit.project,
- project_id: commit.project_id,
- notify_only_broken_builds: false,
- hipchat_room: 123,
- hipchat_token: 'a1b2c3d4e5f6'
- )
-
- WebMock.stub_request(:post, api_url)
- end
-
-
- it "should call the HipChat API" do
- service.execute(build)
- Ci::HipChatNotifierWorker.drain
-
- expect( WebMock ).to have_requested(:post, api_url).once
- end
-
- it "calls the worker with expected arguments" do
- expect( Ci::HipChatNotifierWorker ).to receive(:perform_async) \
- .with(an_instance_of(String), hash_including(
- token: 'a1b2c3d4e5f6',
- room: 123,
- server: 'https://api.hipchat.com',
- color: 'red',
- notify: true
- ))
-
- service.execute(build)
- end
- end
-end
diff --git a/spec/models/ci/project_services/mail_service_spec.rb b/spec/models/ci/project_services/mail_service_spec.rb
deleted file mode 100644
index d9b3d34ff15..00000000000
--- a/spec/models/ci/project_services/mail_service_spec.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-require 'spec_helper'
-
-describe Ci::MailService do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Validations" do
- context "active" do
- before do
- subject.active = true
- end
- end
- end
-
- describe 'Sends email for' do
- let(:mail) { Ci::MailService.new }
- let(:user) { User.new(notification_email: 'git@example.com')}
-
- describe 'failed build' do
- let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) }
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- should_email("git@example.com")
- mail.execute(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).to receive(:build_fail_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_success_email).with(build.id, email)
- end
- end
-
- describe 'successfull build' do
- let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) }
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- should_email("git@example.com")
- mail.execute(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
- end
- end
-
- describe 'successfull build and project has email_recipients' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: false,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- should_email("git@example.com")
- should_email("jeroen@example.com")
- mail.execute(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
- end
- end
-
- describe 'successful build and notify only broken builds' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: true,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- should_email(commit.git_author_email)
- should_email("jeroen@example.com")
- mail.execute(build) if mail.can_execute?(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).not_to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
- end
- end
-
- describe 'successful build and can test service' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: false,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- build
- end
-
- it do
- expect(mail.can_test?).to eq(true)
- end
- end
-
- describe 'retried build should not receive email' do
- let(:project) do
- FactoryGirl.create(:ci_project,
- email_add_pusher: true,
- email_only_broken_builds: true,
- email_recipients: "jeroen@example.com")
- end
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
-
- before do
- allow(mail).to receive_messages(
- project: project
- )
- end
-
- it do
- Ci::Build.retry(build)
- should_email(commit.git_author_email)
- should_email("jeroen@example.com")
- mail.execute(build) if mail.can_execute?(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).not_to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
- end
- end
- end
-end
diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb
deleted file mode 100644
index 8adda6c86cc..00000000000
--- a/spec/models/ci/project_services/slack_message_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'spec_helper'
-
-describe Ci::SlackMessage do
- subject { Ci::SlackMessage.new(commit) }
-
- let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
-
- context 'when all matrix builds succeeded' do
- let(:color) { 'good' }
-
- it 'returns a message with success' do
- commit.create_builds('master', false, nil)
- commit.builds.update_all(status: "success")
- commit.reload
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Commit')
- expect(subject.fallback).to include("\##{commit.id}")
- expect(subject.fallback).to include('succeeded')
- expect(subject.attachments.first[:fields]).to be_empty
- end
- end
-
- context 'when one of matrix builds failed' do
- let(:color) { 'danger' }
-
- it 'returns a message with information about failed build' do
- commit.create_builds('master', false, nil)
- first_build = commit.builds.first
- second_build = commit.builds.last
- first_build.update(status: "success")
- second_build.update(status: "failed")
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Commit')
- expect(subject.fallback).to include("\##{commit.id}")
- expect(subject.fallback).to include('failed')
- expect(subject.attachments.first[:fields].size).to eq(1)
- expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
- expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
- end
- end
-end
diff --git a/spec/models/ci/project_services/slack_service_spec.rb b/spec/models/ci/project_services/slack_service_spec.rb
deleted file mode 100644
index 1ac7dfe568d..00000000000
--- a/spec/models/ci/project_services/slack_service_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-require 'spec_helper'
-
-describe Ci::SlackService do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Validations" do
- context "active" do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of :webhook }
- end
- end
-
- describe "Execute" do
- let(:slack) { Ci::SlackService.new }
- let(:commit) { FactoryGirl.create :ci_commit }
- let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
- let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
- let(:notify_only_broken_builds) { false }
-
- before do
- allow(slack).to receive_messages(
- project: commit.project,
- project_id: commit.project_id,
- webhook: webhook_url,
- notify_only_broken_builds: notify_only_broken_builds
- )
-
- WebMock.stub_request(:post, webhook_url)
- end
-
- it "should call Slack API" do
- slack.execute(build)
- Ci::SlackNotifierWorker.drain
-
- expect(WebMock).to have_requested(:post, webhook_url).once
- end
- end
-end
diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb
deleted file mode 100644
index ac7e38bbcb0..00000000000
--- a/spec/models/ci/project_spec.rb
+++ /dev/null
@@ -1,246 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_projects
-#
-# id :integer not null, primary key
-# name :string(255)
-# timeout :integer default(3600), not null
-# created_at :datetime
-# updated_at :datetime
-# token :string(255)
-# default_ref :string(255)
-# path :string(255)
-# always_build :boolean default(FALSE), not null
-# polling_interval :integer
-# public :boolean default(FALSE), not null
-# ssh_url_to_repo :string(255)
-# gitlab_id :integer
-# allow_git_fetch :boolean default(TRUE), not null
-# email_recipients :string(255) default(""), not null
-# email_add_pusher :boolean default(TRUE), not null
-# email_only_broken_builds :boolean default(TRUE), not null
-# skip_refs :string(255)
-# coverage_regex :string(255)
-# shared_runners_enabled :boolean default(FALSE)
-# generated_yaml_config :text
-#
-
-require 'spec_helper'
-
-describe Ci::Project do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { project.gl_project }
- subject { project }
-
- it { is_expected.to have_many(:runner_projects) }
- it { is_expected.to have_many(:runners) }
- it { is_expected.to have_many(:web_hooks) }
- it { is_expected.to have_many(:events) }
- it { is_expected.to have_many(:variables) }
- it { is_expected.to have_many(:triggers) }
- it { is_expected.to have_many(:services) }
-
- it { is_expected.to validate_presence_of :timeout }
- it { is_expected.to validate_presence_of :gitlab_id }
-
- describe 'before_validation' do
- it 'should set an random token if none provided' do
- project = FactoryGirl.create :ci_project_without_token
- expect(project.token).not_to eq("")
- end
-
- it 'should not set an random toke if one provided' do
- project = FactoryGirl.create :ci_project
- expect(project.token).to eq("iPWx6WM4lhHNedGfBpPJNP")
- end
- end
-
- describe :name_with_namespace do
- subject { project.name_with_namespace }
-
- it { is_expected.to eq(project.name) }
- it { is_expected.to eq(gl_project.name_with_namespace) }
- end
-
- describe :path_with_namespace do
- subject { project.path_with_namespace }
-
- it { is_expected.to eq(project.path) }
- it { is_expected.to eq(gl_project.path_with_namespace) }
- end
-
- describe :path_with_namespace do
- subject { project.web_url }
-
- it { is_expected.to eq(gl_project.web_url) }
- end
-
- describe :web_url do
- subject { project.web_url }
-
- it { is_expected.to eq(project.gitlab_url) }
- it { is_expected.to eq(gl_project.web_url) }
- end
-
- describe :http_url_to_repo do
- subject { project.http_url_to_repo }
-
- it { is_expected.to eq(gl_project.http_url_to_repo) }
- end
-
- describe :ssh_url_to_repo do
- subject { project.ssh_url_to_repo }
-
- it { is_expected.to eq(gl_project.ssh_url_to_repo) }
- end
-
- describe :commits do
- subject { project.commits }
-
- before do
- FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
- end
-
- it { is_expected.to eq(gl_project.ci_commits) }
- end
-
- describe :builds do
- subject { project.builds }
-
- before do
- commit = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
- FactoryGirl.create :ci_build, commit: commit
- end
-
- it { is_expected.to eq(gl_project.ci_builds) }
- end
-
- describe "ordered_by_last_commit_date" do
- it "returns ordered projects" do
- newest_project = FactoryGirl.create :empty_project
- newest_ci_project = newest_project.ensure_gitlab_ci_project
- oldest_project = FactoryGirl.create :empty_project
- oldest_ci_project = oldest_project.ensure_gitlab_ci_project
- project_without_commits = FactoryGirl.create :empty_project
- ci_project_without_commits = project_without_commits.ensure_gitlab_ci_project
-
- FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: newest_project
- FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: oldest_project
-
- expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_ci_project, oldest_ci_project, ci_project_without_commits])
- end
- end
-
- context :valid_project do
- let(:commit) { FactoryGirl.create(:ci_commit) }
-
- context :project_with_commit_and_builds do
- let(:project) { commit.project }
-
- before do
- FactoryGirl.create(:ci_build, commit: commit)
- end
-
- it { expect(project.status).to eq('pending') }
- it { expect(project.last_commit).to be_kind_of(Ci::Commit) }
- it { expect(project.human_status).to eq('pending') }
- end
- end
-
- describe '#email_notification?' do
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- expect(project.email_notification?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: false, email_recipients: 'test tesft'
- expect(project.email_notification?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: false, email_recipients: ''
- expect(project.email_notification?).to eq(false)
- end
- end
-
- describe '#broken_or_success?' do
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(true)
- allow(project).to receive(:success?).and_return(true)
- expect(project.broken_or_success?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(true)
- allow(project).to receive(:success?).and_return(false)
- expect(project.broken_or_success?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(false)
- allow(project).to receive(:success?).and_return(true)
- expect(project.broken_or_success?).to eq(true)
- end
-
- it do
- project = FactoryGirl.create :ci_project, email_add_pusher: true
- allow(project).to receive(:broken?).and_return(false)
- allow(project).to receive(:success?).and_return(false)
- expect(project.broken_or_success?).to eq(false)
- end
- end
-
- describe :repo_url_with_auth do
- let(:project) { FactoryGirl.create :ci_project }
- subject { project.repo_url_with_auth }
-
- it { is_expected.to be_a(String) }
- it { is_expected.to end_with(".git") }
- it { is_expected.to start_with(project.gitlab_url[0..6]) }
- it { is_expected.to include(project.token) }
- it { is_expected.to include('gitlab-ci-token') }
- it { is_expected.to include(project.gitlab_url[7..-1]) }
- end
-
- describe :any_runners do
- it "there are no runners available" do
- project = FactoryGirl.create(:ci_project)
- expect(project.any_runners?).to be_falsey
- end
-
- it "there is a specific runner" do
- project = FactoryGirl.create(:ci_project)
- project.runners << FactoryGirl.create(:ci_specific_runner)
- expect(project.any_runners?).to be_truthy
- end
-
- it "there is a shared runner" do
- project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
- FactoryGirl.create(:ci_shared_runner)
- expect(project.any_runners?).to be_truthy
- end
-
- it "there is a shared runner, but they are prohibited to use" do
- project = FactoryGirl.create(:ci_project)
- FactoryGirl.create(:ci_shared_runner)
- expect(project.any_runners?).to be_falsey
- end
-
- it "checks the presence of specific runner" do
- project = FactoryGirl.create(:ci_project)
- specific_runner = FactoryGirl.create(:ci_specific_runner)
- project.runners << specific_runner
- expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
- end
-
- it "checks the presence of shared runner" do
- project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
- shared_runner = FactoryGirl.create(:ci_shared_runner)
- expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
- end
- end
-end
diff --git a/spec/models/ci/runner_project_spec.rb b/spec/models/ci/runner_project_spec.rb
index 37682c6ea0c..da8491357a5 100644
--- a/spec/models/ci/runner_project_spec.rb
+++ b/spec/models/ci/runner_project_spec.rb
@@ -11,6 +11,6 @@
require 'spec_helper'
-describe Ci::RunnerProject do
+describe Ci::RunnerProject, models: true do
pending "add some examples to (or delete) #{__FILE__}"
end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 9a1233b9095..232760dfeba 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -19,7 +19,7 @@
require 'spec_helper'
-describe Ci::Runner do
+describe Ci::Runner, models: true do
describe '#display_name' do
it 'should return the description if it has a value' do
runner = FactoryGirl.build(:ci_runner, description: 'Linux/Ruby-1.9.3-p448')
@@ -38,7 +38,7 @@ describe Ci::Runner do
end
describe :assign_to do
- let!(:project) { FactoryGirl.create :ci_project }
+ let!(:project) { FactoryGirl.create :empty_project }
let!(:shared_runner) { FactoryGirl.create(:ci_shared_runner) }
before { shared_runner.assign_to(project) }
@@ -116,8 +116,8 @@ describe Ci::Runner do
describe "belongs_to_one_project?" do
it "returns false if there are two projects runner assigned to" do
runner = FactoryGirl.create(:ci_specific_runner)
- project = FactoryGirl.create(:ci_project)
- project1 = FactoryGirl.create(:ci_project)
+ project = FactoryGirl.create(:empty_project)
+ project1 = FactoryGirl.create(:empty_project)
project.runners << runner
project1.runners << runner
@@ -126,7 +126,7 @@ describe Ci::Runner do
it "returns true" do
runner = FactoryGirl.create(:ci_specific_runner)
- project = FactoryGirl.create(:ci_project)
+ project = FactoryGirl.create(:empty_project)
project.runners << runner
expect(runner.belongs_to_one_project?).to be_truthy
diff --git a/spec/models/ci/service_spec.rb b/spec/models/ci/service_spec.rb
deleted file mode 100644
index 36cda988eb4..00000000000
--- a/spec/models/ci/service_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-#
-
-require 'spec_helper'
-
-describe Ci::Service do
-
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Mass assignment" do
- end
-
- describe "Test Button" do
- before do
- @service = Ci::Service.new
- end
-
- describe "Testable" do
- let(:commit) { FactoryGirl.create :ci_commit }
- let(:build) { FactoryGirl.create :ci_build, commit: commit }
-
- before do
- allow(@service).to receive_messages(
- project: commit.project
- )
- build
- @testable = @service.can_test?
- end
-
- describe :can_test do
- it { expect(@testable).to eq(true) }
- end
- end
- end
-end
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index b8aa3c1e777..cb2f51e2011 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -12,8 +12,8 @@
require 'spec_helper'
-describe Ci::Trigger do
- let(:project) { FactoryGirl.create :ci_project }
+describe Ci::Trigger, models: true do
+ let(:project) { FactoryGirl.create :empty_project }
describe 'before_validation' do
it 'should set an random token if none provided' do
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index a515f5881ff..31b56953a13 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -13,7 +13,7 @@
require 'spec_helper'
-describe Ci::Variable do
+describe Ci::Variable, models: true do
subject { Ci::Variable.new }
let(:secret_value) { 'secret' }
diff --git a/spec/models/ci/web_hook_spec.rb b/spec/models/ci/web_hook_spec.rb
deleted file mode 100644
index 2865482a212..00000000000
--- a/spec/models/ci/web_hook_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# == Schema Information
-#
-# Table name: ci_web_hooks
-#
-# id :integer not null, primary key
-# url :string(255) not null
-# project_id :integer not null
-# created_at :datetime
-# updated_at :datetime
-#
-
-require 'spec_helper'
-
-describe Ci::WebHook do
- describe "Associations" do
- it { is_expected.to belong_to :project }
- end
-
- describe "Validations" do
- it { is_expected.to validate_presence_of(:url) }
-
- context "url format" do
- it { is_expected.to allow_value("http://example.com").for(:url) }
- it { is_expected.to allow_value("https://excample.com").for(:url) }
- it { is_expected.to allow_value("http://test.com/api").for(:url) }
- it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) }
- it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) }
-
- it { is_expected.not_to allow_value("example.com").for(:url) }
- it { is_expected.not_to allow_value("ftp://example.com").for(:url) }
- it { is_expected.not_to allow_value("herp-and-derp").for(:url) }
- end
- end
-
- describe "execute" do
- before(:each) do
- @web_hook = FactoryGirl.create(:ci_web_hook)
- @project = @web_hook.project
- @data = { before: 'oldrev', after: 'newrev', ref: 'ref' }
-
- WebMock.stub_request(:post, @web_hook.url)
- end
-
- it "POSTs to the web hook URL" do
- @web_hook.execute(@data)
- expect(WebMock).to have_requested(:post, @web_hook.url).once
- end
-
- it "POSTs the data as JSON" do
- json = @data.to_json
-
- @web_hook.execute(@data)
- expect(WebMock).to have_requested(:post, @web_hook.url).with(body: json).once
- end
-
- it "catches exceptions" do
- expect(Ci::WebHook).to receive(:post).and_raise("Some HTTP Post error")
-
- expect{ @web_hook.execute(@data) }.
- to raise_error(RuntimeError, 'Some HTTP Post error')
- end
- end
-end
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index 1031af097bd..9307d97e214 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -1,56 +1,78 @@
require 'spec_helper'
-describe CommitRange do
+describe CommitRange, models: true do
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(Referable) }
end
- let(:sha_from) { 'f3f85602' }
- let(:sha_to) { 'e86e1013' }
+ let!(:project) { create(:project, :public) }
+ let!(:commit1) { project.commit("HEAD~2") }
+ let!(:commit2) { project.commit }
- let(:range) { described_class.new("#{sha_from}...#{sha_to}") }
- let(:range2) { described_class.new("#{sha_from}..#{sha_to}") }
+ let(:sha_from) { commit1.short_id }
+ let(:sha_to) { commit2.short_id }
+
+ let(:full_sha_from) { commit1.id }
+ let(:full_sha_to) { commit2.id }
+
+ let(:range) { described_class.new("#{sha_from}...#{sha_to}", project) }
+ let(:range2) { described_class.new("#{sha_from}..#{sha_to}", project) }
it 'raises ArgumentError when given an invalid range string' do
- expect { described_class.new("Foo") }.to raise_error(ArgumentError)
+ expect { described_class.new("Foo", project) }.to raise_error(ArgumentError)
end
describe '#to_s' do
it 'is correct for three-dot syntax' do
- expect(range.to_s).to eq "#{sha_from[0..7]}...#{sha_to[0..7]}"
+ expect(range.to_s).to eq "#{full_sha_from}...#{full_sha_to}"
end
it 'is correct for two-dot syntax' do
- expect(range2.to_s).to eq "#{sha_from[0..7]}..#{sha_to[0..7]}"
+ expect(range2.to_s).to eq "#{full_sha_from}..#{full_sha_to}"
end
end
describe '#to_reference' do
- let(:project) { double('project', to_reference: 'namespace1/project') }
+ let(:cross) { create(:project) }
+
+ it 'returns a String reference to the object' do
+ expect(range.to_reference).to eq "#{full_sha_from}...#{full_sha_to}"
+ end
+
+ it 'returns a String reference to the object' do
+ expect(range2.to_reference).to eq "#{full_sha_from}..#{full_sha_to}"
+ end
+
+ it 'supports a cross-project reference' do
+ expect(range.to_reference(cross)).to eq "#{project.to_reference}@#{full_sha_from}...#{full_sha_to}"
+ end
+ end
- before do
- range.project = project
+ describe '#reference_link_text' do
+ let(:cross) { create(:project) }
+
+ it 'returns a String reference to the object' do
+ expect(range.reference_link_text).to eq "#{sha_from}...#{sha_to}"
end
it 'returns a String reference to the object' do
- expect(range.to_reference).to eq range.to_s
+ expect(range2.reference_link_text).to eq "#{sha_from}..#{sha_to}"
end
it 'supports a cross-project reference' do
- cross = double('project')
- expect(range.to_reference(cross)).to eq "#{project.to_reference}@#{range.to_s}"
+ expect(range.reference_link_text(cross)).to eq "#{project.to_reference}@#{sha_from}...#{sha_to}"
end
end
describe '#reference_title' do
it 'returns the correct String for three-dot ranges' do
- expect(range.reference_title).to eq "Commits #{sha_from} through #{sha_to}"
+ expect(range.reference_title).to eq "Commits #{full_sha_from} through #{full_sha_to}"
end
it 'returns the correct String for two-dot ranges' do
- expect(range2.reference_title).to eq "Commits #{sha_from}^ through #{sha_to}"
+ expect(range2.reference_title).to eq "Commits #{full_sha_from}^ through #{full_sha_to}"
end
end
@@ -60,11 +82,11 @@ describe CommitRange do
end
it 'includes the correct values for a three-dot range' do
- expect(range.to_param).to eq({ from: sha_from, to: sha_to })
+ expect(range.to_param).to eq({ from: full_sha_from, to: full_sha_to })
end
it 'includes the correct values for a two-dot range' do
- expect(range2.to_param).to eq({ from: sha_from + '^', to: sha_to })
+ expect(range2.to_param).to eq({ from: full_sha_from + '^', to: full_sha_to })
end
end
@@ -79,64 +101,37 @@ describe CommitRange do
end
describe '#valid_commits?' do
- context 'without a project' do
- it 'returns nil' do
- expect(range.valid_commits?).to be_nil
+ context 'with a valid repo' do
+ before do
+ expect(project).to receive(:valid_repo?).and_return(true)
end
- end
-
- it 'accepts an optional project argument' do
- project1 = double('project1').as_null_object
- project2 = double('project2').as_null_object
-
- # project1 gets assigned through the accessor, but ignored when not given
- # as an argument to `valid_commits?`
- expect(project1).not_to receive(:present?)
- range.project = project1
-
- # project2 gets passed to `valid_commits?`
- expect(project2).to receive(:present?).and_return(false)
- range.valid_commits?(project2)
- end
-
- context 'with a project' do
- let(:project) { double('project', repository: double('repository')) }
+ it 'is false when `sha_from` is invalid' do
+ expect(project).to receive(:commit).with(sha_from).and_return(nil)
+ expect(project).to receive(:commit).with(sha_to).and_call_original
- context 'with a valid repo' do
- before do
- expect(project).to receive(:valid_repo?).and_return(true)
- range.project = project
- end
+ expect(range).not_to be_valid_commits
+ end
- it 'is false when `sha_from` is invalid' do
- expect(project.repository).to receive(:commit).with(sha_from).and_return(false)
- expect(project.repository).not_to receive(:commit).with(sha_to)
- expect(range).not_to be_valid_commits
- end
+ it 'is false when `sha_to` is invalid' do
+ expect(project).to receive(:commit).with(sha_from).and_call_original
+ expect(project).to receive(:commit).with(sha_to).and_return(nil)
- it 'is false when `sha_to` is invalid' do
- expect(project.repository).to receive(:commit).with(sha_from).and_return(true)
- expect(project.repository).to receive(:commit).with(sha_to).and_return(false)
- expect(range).not_to be_valid_commits
- end
+ expect(range).not_to be_valid_commits
+ end
- it 'is true when both `sha_from` and `sha_to` are valid' do
- expect(project.repository).to receive(:commit).with(sha_from).and_return(true)
- expect(project.repository).to receive(:commit).with(sha_to).and_return(true)
- expect(range).to be_valid_commits
- end
+ it 'is true when both `sha_from` and `sha_to` are valid' do
+ expect(range).to be_valid_commits
end
+ end
- context 'without a valid repo' do
- before do
- expect(project).to receive(:valid_repo?).and_return(false)
- range.project = project
- end
+ context 'without a valid repo' do
+ before do
+ expect(project).to receive(:valid_repo?).and_return(false)
+ end
- it 'returns false' do
- expect(range).not_to be_valid_commits
- end
+ it 'returns false' do
+ expect(range).not_to be_valid_commits
end
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 90be9324951..ecf37b40c58 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Commit do
+describe Commit, models: true do
let(:project) { create(:project) }
let(:commit) { project.commit }
@@ -24,6 +24,17 @@ describe Commit do
end
end
+ describe '#reference_link_text' do
+ it 'returns a String reference to the object' do
+ expect(commit.reference_link_text).to eq commit.short_id
+ end
+
+ it 'supports a cross-project reference' do
+ cross = double('project')
+ expect(commit.reference_link_text(cross)).to eq "#{project.to_reference}@#{commit.short_id}"
+ end
+ end
+
describe '#title' do
it "returns no_commit_message when safe_message is blank" do
allow(commit).to receive(:safe_message).and_return('')
@@ -77,14 +88,10 @@ eos
let(:other_issue) { create :issue, project: other_project }
it 'detects issues that this commit is marked as closing' do
- allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid}")
- expect(commit.closes_issues).to eq([issue])
- end
-
- it 'does not detect issues from other projects' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
- allow(commit).to receive(:safe_message).and_return("Fixes #{ext_ref}")
- expect(commit.closes_issues).to be_empty
+ allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid} and #{ext_ref}")
+ expect(commit.closes_issues).to include(issue)
+ expect(commit.closes_issues).to include(other_issue)
end
end
@@ -100,4 +107,15 @@ eos
# Include the subject in the repository stub.
let(:extra_commits) { [subject] }
end
+
+ describe '#hook_attrs' do
+ let(:data) { commit.hook_attrs(with_changed_files: true) }
+
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:message]).to include('Add submodule from gitlab.com') }
+ it { expect(data[:timestamp]).to eq('2014-02-27T11:01:38+02:00') }
+ it { expect(data[:added]).to eq(["gitlab-grack"]) }
+ it { expect(data[:modified]).to eq([".gitmodules"]) }
+ it { expect(data[:removed]).to eq([]) }
+ end
end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index dca0715eed8..b8f901b3433 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -33,18 +33,19 @@
require 'spec_helper'
-describe CommitStatus do
+describe CommitStatus, models: true do
let(:commit) { FactoryGirl.create :ci_commit }
let(:commit_status) { FactoryGirl.create :commit_status, commit: commit }
it { is_expected.to belong_to(:commit) }
it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:project) }
+
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_inclusion_of(:status).in_array(%w(pending running failed success canceled)) }
it { is_expected.to delegate_method(:sha).to(:commit) }
it { is_expected.to delegate_method(:short_sha).to(:commit) }
- it { is_expected.to delegate_method(:gl_project).to(:commit) }
it { is_expected.to respond_to :success? }
it { is_expected.to respond_to :failed? }
diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb
index f7ed30f8198..25b3f4e50da 100644
--- a/spec/models/concerns/case_sensitivity_spec.rb
+++ b/spec/models/concerns/case_sensitivity_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CaseSensitivity do
+describe CaseSensitivity, models: true do
describe '.iwhere' do
let(:connection) { ActiveRecord::Base.connection }
let(:model) { Class.new { include CaseSensitivity } }
diff --git a/spec/models/concerns/strip_attribute_spec.rb b/spec/models/concerns/strip_attribute_spec.rb
new file mode 100644
index 00000000000..6445e29c3ef
--- /dev/null
+++ b/spec/models/concerns/strip_attribute_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Milestone, "StripAttribute" do
+ let(:milestone) { create(:milestone) }
+
+ describe ".strip_attributes" do
+ it { expect(Milestone).to respond_to(:strip_attributes) }
+ it { expect(Milestone.strip_attrs).to include(:title) }
+ end
+
+ describe "#strip_attributes" do
+ before do
+ milestone.title = ' 8.3 '
+ milestone.valid?
+ end
+
+ it { expect(milestone.title).to eq('8.3') }
+ end
+
+end
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
new file mode 100644
index 00000000000..a9b0b64e5de
--- /dev/null
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+shared_examples 'TokenAuthenticatable' do
+ describe 'dynamically defined methods' do
+ it { expect(described_class).to be_private_method_defined(:generate_token_for) }
+ it { expect(described_class).to respond_to("find_by_#{token_field}") }
+ it { is_expected.to respond_to("ensure_#{token_field}") }
+ it { is_expected.to respond_to("reset_#{token_field}!") }
+ end
+end
+
+describe User, 'TokenAuthenticatable' do
+ let(:token_field) { :authentication_token }
+ it_behaves_like 'TokenAuthenticatable'
+
+ describe 'ensures authentication token' do
+ subject { create(:user).send(token_field) }
+ it { is_expected.to be_a String }
+ end
+end
+
+describe ApplicationSetting, 'TokenAuthenticatable' do
+ let(:token_field) { :runners_registration_token }
+ it_behaves_like 'TokenAuthenticatable'
+
+ describe 'generating new token' do
+ subject { described_class.new }
+ let(:token) { subject.send(token_field) }
+
+ context 'token is not generated yet' do
+ it { expect(token).to be nil }
+
+ describe 'ensured token' do
+ subject { described_class.new.send("ensure_#{token_field}") }
+
+ it { is_expected.to be_a String }
+ it { is_expected.to_not be_blank }
+ end
+ end
+
+ context 'token is generated' do
+ before { subject.send("reset_#{token_field}!") }
+ it { expect(token).to be_a String }
+ end
+ end
+
+ describe 'multiple token fields' do
+ before do
+ described_class.send(:add_authentication_token_field, :yet_another_token)
+ end
+
+ describe '.token_fields' do
+ subject { described_class.authentication_token_fields }
+ it { is_expected.to include(:runners_registration_token, :yet_another_token) }
+ end
+ end
+end
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index 95729932459..64ba778afea 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -15,7 +15,7 @@
require 'spec_helper'
-describe DeployKey do
+describe DeployKey, models: true do
let(:project) { create(:project) }
let(:deploy_key) { create(:deploy_key, projects: [project]) }
diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb
index 0eb22599d18..8aedbfb8636 100644
--- a/spec/models/deploy_keys_project_spec.rb
+++ b/spec/models/deploy_keys_project_spec.rb
@@ -11,7 +11,7 @@
require 'spec_helper'
-describe DeployKeysProject do
+describe DeployKeysProject, models: true do
describe "Associations" do
it { is_expected.to belong_to(:deploy_key) }
it { is_expected.to belong_to(:project) }
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index ae53f7a536b..071582b0282 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -16,7 +16,7 @@
require 'spec_helper'
-describe Event do
+describe Event, models: true do
describe "Associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:target) }
diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb
index 7744610db78..6ec6b9037a4 100644
--- a/spec/models/external_issue_spec.rb
+++ b/spec/models/external_issue_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ExternalIssue do
+describe ExternalIssue, models: true do
let(:project) { double('project', to_reference: 'namespace1/project1') }
let(:issue) { described_class.new('EXT-1234', project) }
diff --git a/spec/models/external_wiki_service_spec.rb b/spec/models/external_wiki_service_spec.rb
index 4bd5b0be61c..b198aa77526 100644
--- a/spec/models/external_wiki_service_spec.rb
+++ b/spec/models/external_wiki_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe ExternalWikiService do
+describe ExternalWikiService, models: true do
include ExternalWikiHelper
describe "Associations" do
it { should belong_to :project }
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index c86314c454c..d61c1c96bde 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -33,7 +33,7 @@
require 'spec_helper'
-describe GenericCommitStatus do
+describe GenericCommitStatus, models: true do
let(:commit) { FactoryGirl.create :ci_commit }
let(:generic_commit_status) { FactoryGirl.create :generic_commit_status, commit: commit }
diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb
index 6eeff30b20e..ba03e6aabd0 100644
--- a/spec/models/global_milestone_spec.rb
+++ b/spec/models/global_milestone_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GlobalMilestone do
+describe GlobalMilestone, models: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 6f166b5ab75..646f767e6fe 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -16,7 +16,7 @@
require 'spec_helper'
-describe Group do
+describe Group, models: true do
let!(:group) { create(:group) }
describe 'associations' do
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index a2dc66fce3e..645ee0b929a 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -18,7 +18,7 @@
require 'spec_helper'
-describe ProjectHook do
+describe ProjectHook, models: true do
describe '.push_hooks' do
it 'should return hooks for push events only' do
hook = create(:project_hook, push_events: true)
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index 16641c12124..1455661485b 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -18,7 +18,7 @@
require "spec_helper"
-describe ServiceHook do
+describe ServiceHook, models: true do
describe "Associations" do
it { is_expected.to belong_to :service }
end
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index 02d2cc2c77a..138b87a9a06 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -18,7 +18,7 @@
require "spec_helper"
-describe SystemHook do
+describe SystemHook, models: true do
describe "execute" do
before(:each) do
@system_hook = create(:system_hook)
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 2fdc49f02ee..2d90b0793cc 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -18,7 +18,7 @@
require 'spec_helper'
-describe ProjectHook do
+describe ProjectHook, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
end
@@ -71,5 +71,11 @@ describe ProjectHook do
expect { @project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError)
end
+
+ it "handles SSL exceptions" do
+ expect(WebHook).to receive(:post).and_raise(OpenSSL::SSL::SSLError.new('SSL error'))
+
+ expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error'])
+ end
end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index c9aa1b063c6..52271c7c8c6 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe Issue do
+describe Issue, models: true do
describe "Associations" do
it { is_expected.to belong_to(:milestone) }
end
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 2f819f60cbb..c962b83644a 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -15,7 +15,7 @@
require 'spec_helper'
-describe Key do
+describe Key, models: true do
describe "Associations" do
it { is_expected.to belong_to(:user) }
end
@@ -81,7 +81,7 @@ describe Key do
it 'rejects the multiple line key' do
key = build(:key)
- key.key.gsub!(' ', "\n")
+ key.key.tr!(' ', "\n")
expect(key).not_to be_valid
end
end
diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb
index 8c240826582..dc7510b1de3 100644
--- a/spec/models/label_link_spec.rb
+++ b/spec/models/label_link_spec.rb
@@ -12,7 +12,7 @@
require 'spec_helper'
-describe LabelLink do
+describe LabelLink, models: true do
let(:label) { create(:label_link) }
it { expect(label).to be_valid }
diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb
index 511ee8cbd96..696fbf7e0aa 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -13,7 +13,7 @@
require 'spec_helper'
-describe Label do
+describe Label, models: true do
let(:label) { create(:label) }
describe 'associations' do
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 57f840c1e91..2aedca20df2 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -19,7 +19,7 @@
require 'spec_helper'
-describe Member do
+describe Member, models: true do
describe "Associations" do
it { is_expected.to belong_to(:user) }
end
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 652026729bb..5424c9b9cba 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -19,7 +19,7 @@
require 'spec_helper'
-describe GroupMember do
+describe GroupMember, models: true do
context 'notification' do
describe "#after_create" do
it "should send email to user" do
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index ee912bf12a2..9f26d9eb5ce 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -19,7 +19,7 @@
require 'spec_helper'
-describe ProjectMember do
+describe ProjectMember, models: true do
describe :import_team do
before do
@abilities = Six.new
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 90af75ff0e3..1aeba9b2b3b 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -25,13 +25,13 @@
require 'spec_helper'
-describe MergeRequest do
+describe MergeRequest, models: true do
subject { create(:merge_request) }
describe 'associations' do
it { is_expected.to belong_to(:target_project).with_foreign_key(:target_project_id).class_name('Project') }
it { is_expected.to belong_to(:source_project).with_foreign_key(:source_project_id).class_name('Project') }
-
+ it { is_expected.to belong_to(:merge_user).class_name("User") }
it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) }
end
@@ -48,12 +48,32 @@ describe MergeRequest do
describe 'validation' do
it { is_expected.to validate_presence_of(:target_branch) }
it { is_expected.to validate_presence_of(:source_branch) }
+
+ context "Validation of merge user with Merge When Build succeeds" do
+ it "allows user to be nil when the feature is disabled" do
+ expect(subject).to be_valid
+ end
+
+ it "is invalid without merge user" do
+ subject.merge_when_build_succeeds = true
+ expect(subject).not_to be_valid
+ end
+
+ it "is valid with merge user" do
+ subject.merge_when_build_succeeds = true
+ subject.merge_user = build(:user)
+
+ expect(subject).to be_valid
+ end
+ end
end
describe 'respond to' do
it { is_expected.to respond_to(:unchecked?) }
it { is_expected.to respond_to(:can_be_merged?) }
it { is_expected.to respond_to(:cannot_be_merged?) }
+ it { is_expected.to respond_to(:merge_params) }
+ it { is_expected.to respond_to(:merge_when_build_succeeds) }
end
describe '#to_reference' do
@@ -172,6 +192,50 @@ describe MergeRequest do
end
end
+ describe '#can_remove_source_branch?' do
+ let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+
+ before do
+ subject.source_project.team << [user, :master]
+
+ subject.source_branch = "feature"
+ subject.target_branch = "master"
+ subject.save!
+ end
+
+ it "can't be removed when its a protected branch" do
+ allow(subject.source_project).to receive(:protected_branch?).and_return(true)
+ expect(subject.can_remove_source_branch?(user)).to be_falsey
+ end
+
+ it "cant remove a root ref" do
+ subject.source_branch = "master"
+ subject.target_branch = "feature"
+
+ expect(subject.can_remove_source_branch?(user)).to be_falsey
+ end
+
+ it "is unable to remove the source branch for a project the user cannot push to" do
+ expect(subject.can_remove_source_branch?(user2)).to be_falsey
+ end
+
+ it "is can be removed in all other cases" do
+ expect(subject.can_remove_source_branch?(user)).to be_truthy
+ end
+ end
+
+ describe "#reset_merge_when_build_succeeds" do
+ let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user) }
+
+ it "sets the item to false" do
+ merge_if_green.reset_merge_when_build_succeeds
+ merge_if_green.reload
+
+ expect(merge_if_green.merge_when_build_succeeds).to be_falsey
+ end
+ end
+
describe "#hook_attrs" do
it "has all the required keys" do
attrs = subject.hook_attrs
@@ -193,4 +257,29 @@ describe MergeRequest do
it_behaves_like 'a Taskable' do
subject { create :merge_request, :simple }
end
+
+ describe '#ci_commit' do
+ describe 'when the source project exists' do
+ it 'returns the latest commit' do
+ commit = double(:commit, id: '123abc')
+ ci_commit = double(:ci_commit)
+
+ allow(subject).to receive(:last_commit).and_return(commit)
+
+ expect(subject.source_project).to receive(:ci_commit).
+ with('123abc').
+ and_return(ci_commit)
+
+ expect(subject.ci_commit).to eq(ci_commit)
+ end
+ end
+
+ describe 'when the source project does not exist' do
+ it 'returns nil' do
+ allow(subject).to receive(:source_project).and_return(nil)
+
+ expect(subject.ci_commit).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 77c58627322..30a71987d86 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -15,7 +15,7 @@
require 'spec_helper'
-describe Milestone do
+describe Milestone, models: true do
describe "Associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:issues) }
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index a98b9cb7321..4fa2d2bc4d2 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -16,7 +16,7 @@
require 'spec_helper'
-describe Namespace do
+describe Namespace, models: true do
let!(:namespace) { create(:namespace) }
it { is_expected.to have_many :projects }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index f347f537550..216c7dabae0 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -16,11 +16,12 @@
# system :boolean default(FALSE), not null
# st_diff :text
# updated_by_id :integer
+# is_award :boolean default(FALSE), not null
#
require 'spec_helper'
-describe Note do
+describe Note, models: true do
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:noteable) }
@@ -141,4 +142,30 @@ describe Note do
expect(Note.grouped_awards.first.last).to match_array(Note.all)
end
end
+
+ describe "editable?" do
+ it "returns true" do
+ note = build(:note)
+ expect(note.editable?).to be_truthy
+ end
+
+ it "returns false" do
+ note = build(:note, system: true)
+ expect(note.editable?).to be_falsy
+ end
+
+ it "returns false" do
+ note = build(:note, is_award: true, note: "smiley")
+ expect(note.editable?).to be_falsy
+ end
+ end
+
+ describe "set_award!" do
+ let(:issue) { create :issue }
+
+ it "converts aliases to actual name" do
+ note = create :note, note: ":thumbsup:", noteable: issue
+ expect(note.reload.note).to eq("+1")
+ end
+ end
end
diff --git a/spec/models/project_security_spec.rb b/spec/models/project_security_spec.rb
index f600a240c46..3643ad1b052 100644
--- a/spec/models/project_security_spec.rb
+++ b/spec/models/project_security_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Project do
+describe Project, models: true do
describe :authorization do
before do
@p1 = create(:project)
diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index 230807ea672..88cd624877a 100644
--- a/spec/models/project_services/buildkite_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe BuildkiteService do
+describe BuildkiteService, models: true do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index e9967f5fe0b..a2cf68a9e38 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe DroneCiService do
+describe DroneCiService, models: true do
describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to have_one(:service_hook) }
diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb
index 16296607a94..ff7fbcaa004 100644
--- a/spec/models/project_services/flowdock_service_spec.rb
+++ b/spec/models/project_services/flowdock_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe FlowdockService do
+describe FlowdockService, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb
index 9e156472316..ecb3ccb1673 100644
--- a/spec/models/project_services/gemnasium_service_spec.rb
+++ b/spec/models/project_services/gemnasium_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe GemnasiumService do
+describe GemnasiumService, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
deleted file mode 100644
index b9006b693b2..00000000000
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# project_id :integer
-# created_at :datetime
-# updated_at :datetime
-# active :boolean default(FALSE), not null
-# properties :text
-# template :boolean default(FALSE)
-# push_events :boolean default(TRUE)
-# issues_events :boolean default(TRUE)
-# merge_requests_events :boolean default(TRUE)
-# tag_push_events :boolean default(TRUE)
-# note_events :boolean default(TRUE), not null
-#
-
-require 'spec_helper'
-
-describe GitlabCiService do
- describe 'associations' do
- it { is_expected.to belong_to(:project) }
- it { is_expected.to have_one(:service_hook) }
- end
-
- describe 'commits methods' do
- before do
- @ci_project = create(:ci_project)
- @service = GitlabCiService.new
- allow(@service).to receive_messages(
- service_hook: true,
- project_url: 'http://ci.gitlab.org/projects/2',
- token: 'verySecret',
- project: @ci_project.gl_project
- )
- end
-
- describe :build_page do
- it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/builds")}
- end
-
- describe "execute" do
- let(:user) { create(:user, username: 'username') }
- let(:project) { create(:project, name: 'project') }
- let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
-
- it "calls CreateCommitService" do
- expect_any_instance_of(Ci::CreateCommitService).to receive(:execute).with(@ci_project, user, push_sample_data)
-
- @service.execute(push_sample_data)
- end
- end
- end
-end
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index e34ca09bffc..3518dbd1728 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe GitlabIssueTrackerService do
+describe GitlabIssueTrackerService, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index f67d7b30980..91dd92b7c67 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe HipchatService do
+describe HipchatService, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -57,23 +57,21 @@ describe HipchatService do
it 'should use v1 if version is provided' do
allow(hipchat).to receive(:api_version).and_return('v1')
- expect(HipChat::Client).to receive(:new).
- with(token,
- api_version: 'v1',
- server_url: server_url).
- and_return(
- double(:hipchat_service).as_null_object)
+ expect(HipChat::Client).to receive(:new).with(
+ token,
+ api_version: 'v1',
+ server_url: server_url
+ ).and_return(double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data)
end
it 'should use v2 as the version when nothing is provided' do
allow(hipchat).to receive(:api_version).and_return('')
- expect(HipChat::Client).to receive(:new).
- with(token,
- api_version: 'v2',
- server_url: server_url).
- and_return(
- double(:hipchat_service).as_null_object)
+ expect(HipChat::Client).to receive(:new).with(
+ token,
+ api_version: 'v2',
+ server_url: server_url
+ ).and_return(double(:hipchat_service).as_null_object)
hipchat.execute(push_sample_data)
end
@@ -247,6 +245,55 @@ describe HipchatService do
end
end
+ context 'build events' do
+ let(:build) { create(:ci_build) }
+ let(:data) { Gitlab::BuildDataBuilder.build(build) }
+
+ context 'for failed' do
+ before { build.drop }
+
+ it "should call Hipchat API" do
+ hipchat.execute(data)
+
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should create a build message" do
+ message = hipchat.send(:create_build_message, data)
+
+ project_url = project.web_url
+ project_name = project.name_with_namespace.gsub(/\s/, '')
+ sha = data[:sha]
+ ref = data[:ref]
+ ref_type = data[:tag] ? 'tag' : 'branch'
+ duration = data[:commit][:duration]
+
+ expect(message).to eq("<a href=\"#{project_url}\">#{project_name}</a>: " \
+ "Commit <a href=\"#{project_url}/commit/#{sha}/builds\">#{Commit.truncate_sha(sha)}</a> " \
+ "of <a href=\"#{project_url}/commits/#{ref}\">#{ref}</a> #{ref_type} " \
+ "by #{data[:commit][:author_name]} failed in #{duration} second(s)")
+ end
+ end
+
+ context 'for succeeded' do
+ before do
+ build.success
+ end
+
+ it "should call Hipchat API" do
+ hipchat.notify_only_broken_builds = false
+ hipchat.execute(data)
+ expect(WebMock).to have_requested(:post, api_url).once
+ end
+
+ it "should notify only broken" do
+ hipchat.notify_only_broken_builds = true
+ hipchat.execute(data)
+ expect(WebMock).to_not have_requested(:post, api_url).once
+ end
+ end
+ end
+
context "#message_options" do
it "should be set to the defaults" do
expect(hipchat.send(:message_options)).to eq({ notify: false, color: 'yellow' })
diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb
index 7d483a44c53..b783b1a576e 100644
--- a/spec/models/project_services/irker_service_spec.rb
+++ b/spec/models/project_services/irker_service_spec.rb
@@ -22,7 +22,7 @@ require 'spec_helper'
require 'socket'
require 'json'
-describe IrkerService do
+describe IrkerService, models: true do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index ddd2cce212c..7d91ebe9ce6 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe JiraService do
+describe JiraService, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -94,9 +94,9 @@ describe JiraService do
end
it 'should be prepopulated with the settings' do
- expect(@service.properties[:project_url]).to eq('http://jira.sample/projects/project_a')
- expect(@service.properties[:issues_url]).to eq("http://jira.sample/issues/:id")
- expect(@service.properties[:new_issue_url]).to eq("http://jira.sample/projects/project_a/issues/new")
+ expect(@service.properties["project_url"]).to eq('http://jira.sample/projects/project_a')
+ expect(@service.properties["issues_url"]).to eq("http://jira.sample/issues/:id")
+ expect(@service.properties["new_issue_url"]).to eq("http://jira.sample/projects/project_a/issues/new")
end
end
end
diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb
index ac10ffbd39b..96039f9491b 100644
--- a/spec/models/project_services/pushover_service_spec.rb
+++ b/spec/models/project_services/pushover_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe PushoverService do
+describe PushoverService, models: true do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_services/slack_service/build_message_spec.rb b/spec/models/project_services/slack_service/build_message_spec.rb
new file mode 100644
index 00000000000..621c83c0cda
--- /dev/null
+++ b/spec/models/project_services/slack_service/build_message_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe SlackService::BuildMessage do
+ subject { SlackService::BuildMessage.new(args) }
+
+ let(:args) do
+ {
+ sha: '97de212e80737a608d939f648d959671fb0a0142',
+ ref: 'develop',
+ tag: false,
+
+ project_name: 'project_name',
+ project_url: 'somewhere.com',
+
+ commit: {
+ status: status,
+ author_name: 'hacker',
+ duration: 10,
+ },
+ }
+ end
+
+ context 'succeeded' do
+ let(:status) { 'success' }
+ let(:color) { 'good' }
+
+ it 'returns a message with information about succeeded build' do
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker passed in 10 second(s)'
+ expect(subject.pretext).to be_empty
+ expect(subject.fallback).to eq(message)
+ expect(subject.attachments).to eq([text: message, color: color])
+ end
+ end
+
+ context 'failed' do
+ let(:status) { 'failed' }
+ let(:color) { 'danger' }
+
+ it 'returns a message with information about failed build' do
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 10 second(s)'
+ expect(subject.pretext).to be_empty
+ expect(subject.fallback).to eq(message)
+ expect(subject.attachments).to eq([text: message, color: color])
+ end
+ end
+end
diff --git a/spec/models/project_services/slack_service/issue_message_spec.rb b/spec/models/project_services/slack_service/issue_message_spec.rb
index b78d92f23a1..97e6f03e308 100644
--- a/spec/models/project_services/slack_service/issue_message_spec.rb
+++ b/spec/models/project_services/slack_service/issue_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackService::IssueMessage do
+describe SlackService::IssueMessage, models: true do
subject { SlackService::IssueMessage.new(args) }
let(:args) do
diff --git a/spec/models/project_services/slack_service/merge_message_spec.rb b/spec/models/project_services/slack_service/merge_message_spec.rb
index 581c50d6c88..dae8bd90922 100644
--- a/spec/models/project_services/slack_service/merge_message_spec.rb
+++ b/spec/models/project_services/slack_service/merge_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackService::MergeMessage do
+describe SlackService::MergeMessage, models: true do
subject { SlackService::MergeMessage.new(args) }
let(:args) do
diff --git a/spec/models/project_services/slack_service/note_message_spec.rb b/spec/models/project_services/slack_service/note_message_spec.rb
index 21fb575480b..06006b9a4f5 100644
--- a/spec/models/project_services/slack_service/note_message_spec.rb
+++ b/spec/models/project_services/slack_service/note_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackService::NoteMessage do
+describe SlackService::NoteMessage, models: true do
let(:color) { '#345' }
before do
@@ -89,10 +89,10 @@ describe SlackService::NoteMessage do
it 'returns a message regarding notes on an issue' do
message = SlackService::NoteMessage.new(@args)
expect(message.pretext).to eq(
- "Test User commented on " \
- "<url|issue #20> in <somewhere.com|project_name>: " \
- "*issue title*")
- expected_attachments = [
+ "Test User commented on " \
+ "<url|issue #20> in <somewhere.com|project_name>: " \
+ "*issue title*")
+ expected_attachments = [
{
text: "comment on an issue",
color: color,
diff --git a/spec/models/project_services/slack_service/push_message_spec.rb b/spec/models/project_services/slack_service/push_message_spec.rb
index ddc290820d1..cda9ee670b0 100644
--- a/spec/models/project_services/slack_service/push_message_spec.rb
+++ b/spec/models/project_services/slack_service/push_message_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SlackService::PushMessage do
+describe SlackService::PushMessage, models: true do
subject { SlackService::PushMessage.new(args) }
let(:args) do
diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb
index 97b60e19e40..a9e0afad90f 100644
--- a/spec/models/project_services/slack_service_spec.rb
+++ b/spec/models/project_services/slack_service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe SlackService do
+describe SlackService, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index 3e8f106d27f..cc92eb0bd9f 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -17,7 +17,7 @@
require 'spec_helper'
-describe ProjectSnippet do
+describe ProjectSnippet, models: true do
describe "Associations" do
it { is_expected.to belong_to(:project) }
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f80fada45e9..c4d3813e9c9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -28,11 +28,12 @@
# import_type :string(255)
# import_source :string(255)
# commit_count :integer default(0)
+# import_error :text
#
require 'spec_helper'
-describe Project do
+describe Project, models: true do
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
@@ -53,6 +54,13 @@ describe Project do
it { is_expected.to have_one(:slack_service).dependent(:destroy) }
it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
it { is_expected.to have_one(:asana_service).dependent(:destroy) }
+ it { is_expected.to have_many(:commit_statuses) }
+ it { is_expected.to have_many(:ci_commits) }
+ it { is_expected.to have_many(:builds) }
+ it { is_expected.to have_many(:runner_projects) }
+ it { is_expected.to have_many(:runners) }
+ it { is_expected.to have_many(:variables) }
+ it { is_expected.to have_many(:triggers) }
end
describe 'modules' do
@@ -87,6 +95,18 @@ describe Project do
expect(project2.errors[:limit_reached].first).to match(/Your project limit is 0/)
end
end
+
+ describe 'project token' do
+ it 'should set an random token if none provided' do
+ project = FactoryGirl.create :empty_project, runners_token: ''
+ expect(project.runners_token).not_to eq('')
+ end
+
+ it 'should not set an random toke if one provided' do
+ project = FactoryGirl.create :empty_project, runners_token: 'my-token'
+ expect(project.runners_token).to eq('my-token')
+ end
+ end
describe 'Respond to' do
it { is_expected.to respond_to(:url_to_repo) }
@@ -152,13 +172,17 @@ describe Project do
describe '#get_issue' do
let(:project) { create(:empty_project) }
- let(:issue) { create(:issue, project: project) }
+ let!(:issue) { create(:issue, project: project) }
context 'with default issues tracker' do
it 'returns an issue' do
expect(project.get_issue(issue.iid)).to eq issue
end
+ it 'returns count of open issues' do
+ expect(project.open_issues_count).to eq(1)
+ end
+
it 'returns nil when no issue found' do
expect(project.get_issue(999)).to be_nil
end
@@ -394,12 +418,7 @@ describe Project do
describe :ci_commit do
let(:project) { create :project }
- let(:commit) { create :ci_commit, gl_project: project }
-
- before do
- project.ensure_gitlab_ci_project
- project.create_gitlab_ci_service(active: true)
- end
+ let(:commit) { create :ci_commit, project: project }
it { expect(project.ci_commit(commit.sha)).to eq(commit) }
end
@@ -411,9 +430,7 @@ describe Project do
subject { project.builds_enabled }
- it { is_expected.to eq(project.gitlab_ci_service.active) }
it { expect(project.builds_enabled?).to be_truthy }
- it { expect(project.gitlab_ci_project).to be_a(Ci::Project) }
end
describe '.trending' do
@@ -444,7 +461,9 @@ describe Project do
before do
2.times do
- create(:note_on_commit, project: project2, created_at: date)
+ # Little fix for special issue related to Fractional Seconds support for MySQL.
+ # See: https://github.com/rails/rails/pull/14359/files
+ create(:note_on_commit, project: project2, created_at: date + 1)
end
end
@@ -472,4 +491,65 @@ describe Project do
it { is_expected.to eq([]) }
end
end
+
+ context 'shared runners by default' do
+ let(:project) { create(:empty_project) }
+
+ subject { project.shared_runners_enabled }
+
+ context 'are enabled' do
+ before { stub_application_setting(shared_runners_enabled: true) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'are disabled' do
+ before { stub_application_setting(shared_runners_enabled: false) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe :any_runners do
+ let(:project) { create(:empty_project, shared_runners_enabled: shared_runners_enabled) }
+ let(:specific_runner) { create(:ci_specific_runner) }
+ let(:shared_runner) { create(:ci_shared_runner) }
+
+ context 'for shared runners disabled' do
+ let(:shared_runners_enabled) { false }
+
+ it 'there are no runners available' do
+ expect(project.any_runners?).to be_falsey
+ end
+
+ it 'there is a specific runner' do
+ project.runners << specific_runner
+ expect(project.any_runners?).to be_truthy
+ end
+
+ it 'there is a shared runner, but they are prohibited to use' do
+ shared_runner
+ expect(project.any_runners?).to be_falsey
+ end
+
+ it 'checks the presence of specific runner' do
+ project.runners << specific_runner
+ expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
+ end
+ end
+
+ context 'for shared runners enabled' do
+ let(:shared_runners_enabled) { true }
+
+ it 'there is a shared runner' do
+ shared_runner
+ expect(project.any_runners?).to be_truthy
+ end
+
+ it 'checks the presence of shared runner' do
+ shared_runner
+ expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 26e8fdae472..5cd5ae327bf 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe ProjectTeam do
+describe ProjectTeam, models: true do
let(:master) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 3b889144447..876b927eaea 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe ProjectWiki do
+describe ProjectWiki, models: true do
let(:project) { create(:empty_project) }
let(:repository) { project.repository }
let(:user) { project.owner }
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index 1e6937b536c..7e956cf6779 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -12,7 +12,7 @@
require 'spec_helper'
-describe ProtectedBranch do
+describe ProtectedBranch, models: true do
describe 'Associations' do
it { is_expected.to belong_to(:project) }
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 319fa0a7c8d..afbf62035ac 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1,9 +1,10 @@
require 'spec_helper'
-describe Repository do
+describe Repository, models: true do
include RepoHelpers
let(:repository) { create(:project).repository }
+ let(:user) { create(:user) }
describe :branch_names_contains do
subject { repository.branch_names_contains(sample_commit.id) }
@@ -99,5 +100,123 @@ describe Repository do
it { expect(subject.startline).to eq(186) }
it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
end
+
+ end
+
+ describe "#license" do
+ before do
+ repository.send(:cache).expire(:license)
+ TestBlob = Struct.new(:name)
+ end
+
+ it 'test selection preference' do
+ files = [TestBlob.new('file'), TestBlob.new('license'), TestBlob.new('copying')]
+ expect(repository.tree).to receive(:blobs).and_return(files)
+
+ expect(repository.license.name).to eq('license')
+ end
+
+ it 'also accepts licence instead of license' do
+ expect(repository.tree).to receive(:blobs).and_return([TestBlob.new('licence')])
+
+ expect(repository.license.name).to eq('licence')
+ end
+ end
+
+ describe :add_branch do
+ context 'when pre hooks were successful' do
+ it 'should run without errors' do
+ hook = double(trigger: true)
+ expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
+
+ expect { repository.add_branch(user, 'new_feature', 'master') }.not_to raise_error
+ end
+
+ it 'should create the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true)
+
+ branch = repository.add_branch(user, 'new_feature', 'master')
+
+ expect(branch.name).to eq('new_feature')
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'should get an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.add_branch(user, 'new_feature', 'master')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+
+ it 'should not create the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.add_branch(user, 'new_feature', 'master')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ expect(repository.find_branch('new_feature')).to be_nil
+ end
+ end
+ end
+
+ describe :rm_branch do
+ context 'when pre hooks were successful' do
+ it 'should run without errors' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true)
+
+ expect { repository.rm_branch(user, 'feature') }.not_to raise_error
+ end
+
+ it 'should delete the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true)
+
+ expect { repository.rm_branch(user, 'feature') }.not_to raise_error
+
+ expect(repository.find_branch('feature')).to be_nil
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'should get an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.rm_branch(user, 'new_feature')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+
+ it 'should not delete the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.rm_branch(user, 'feature')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ expect(repository.find_branch('feature')).not_to be_nil
+ end
+ end
+ end
+
+ describe :commit_with_hooks do
+ context 'when pre hooks were successful' do
+ it 'should run without errors' do
+ expect_any_instance_of(GitHooksService).to receive(:execute).and_return(true)
+
+ expect do
+ repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ end.not_to raise_error
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'should get an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+ end
end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 692e5fda3ba..0ca82365b98 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -20,7 +20,7 @@
require 'spec_helper'
-describe Service do
+describe Service, models: true do
describe "Associations" do
it { is_expected.to belong_to :project }
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 81581838675..eb2dbbdc5a4 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -17,7 +17,7 @@
require 'spec_helper'
-describe Snippet do
+describe Snippet, models: true do
describe 'modules' do
subject { described_class }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 4631b12faf1..376266c0955 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -56,11 +56,12 @@
# project_view :integer default(0)
# consumed_timestep :integer
# layout :integer default(0)
+# hide_project_limit :boolean default(FALSE)
#
require 'spec_helper'
-describe User do
+describe User, models: true do
include Gitlab::CurrentSettings
describe 'modules' do
@@ -91,7 +92,23 @@ describe User do
end
describe 'validations' do
- it { is_expected.to validate_presence_of(:username) }
+ describe 'username' do
+ it 'validates presence' do
+ expect(subject).to validate_presence_of(:username)
+ end
+
+ it 'rejects blacklisted names' do
+ user = build(:user, username: 'dashboard')
+
+ expect(user).not_to be_valid
+ expect(user.errors.values).to eq [['dashboard is a reserved name']]
+ end
+
+ it 'validates uniqueness' do
+ expect(subject).to validate_uniqueness_of(:username)
+ end
+ end
+
it { is_expected.to validate_presence_of(:projects_limit) }
it { is_expected.to validate_numericality_of(:projects_limit) }
it { is_expected.to allow_value(0).for(:projects_limit) }
@@ -445,8 +462,8 @@ describe User do
expect(User.search(user1.username.downcase).to_a).to eq([user1])
expect(User.search(user2.username.upcase).to_a).to eq([user2])
expect(User.search(user2.username.downcase).to_a).to eq([user2])
- expect(User.search(user1.username.downcase).to_a.count).to eq(2)
- expect(User.search(user2.username.downcase).to_a.count).to eq(1)
+ expect(User.search(user1.username.downcase).to_a.size).to eq(2)
+ expect(User.search(user2.username.downcase).to_a.size).to eq(1)
end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index d7802d1734f..c1b03838aa9 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -1,6 +1,6 @@
require "spec_helper"
-describe WikiPage do
+describe WikiPage, models: true do
let(:project) { create(:empty_project) }
let(:user) { project.owner }
let(:wiki) { ProjectWiki.new(project, user) }
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 13cced81875..4cfa49d1566 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -10,6 +10,8 @@ describe API::API, api: true do
let(:avatar_file_path) { File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') }
let!(:group1) { create(:group, avatar: File.open(avatar_file_path)) }
let!(:group2) { create(:group) }
+ let!(:project1) { create(:project, namespace: group1) }
+ let!(:project2) { create(:project, namespace: group2) }
before do
group1.add_owner(user1)
@@ -67,7 +69,7 @@ describe API::API, api: true do
it "should return any existing group" do
get api("/groups/#{group2.id}", admin)
expect(response.status).to eq(200)
- json_response['name'] == group2.name
+ expect(json_response['name']).to eq(group2.name)
end
it "should not return a non existing group" do
@@ -80,7 +82,7 @@ describe API::API, api: true do
it 'should return any existing group' do
get api("/groups/#{group1.path}", admin)
expect(response.status).to eq(200)
- json_response['name'] == group2.name
+ expect(json_response['name']).to eq(group1.name)
end
it 'should not return a non existing group' do
@@ -95,6 +97,59 @@ describe API::API, api: true do
end
end
+ describe "GET /groups/:id/projects" do
+ context "when authenticated as user" do
+ it "should return the group's projects" do
+ get api("/groups/#{group1.id}/projects", user1)
+ expect(response.status).to eq(200)
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['name']).to eq(project1.name)
+ end
+
+ it "should not return a non existing group" do
+ get api("/groups/1328/projects", user1)
+ expect(response.status).to eq(404)
+ end
+
+ it "should not return a group not attached to user1" do
+ get api("/groups/#{group2.id}/projects", user1)
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context "when authenticated as admin" do
+ it "should return any existing group" do
+ get api("/groups/#{group2.id}/projects", admin)
+ expect(response.status).to eq(200)
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['name']).to eq(project2.name)
+ end
+
+ it "should not return a non existing group" do
+ get api("/groups/1328/projects", admin)
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when using group path in URL' do
+ it 'should return any existing group' do
+ get api("/groups/#{group1.path}/projects", admin)
+ expect(response.status).to eq(200)
+ expect(json_response.first['name']).to eq(project1.name)
+ end
+
+ it 'should not return a non existing group' do
+ get api('/groups/unknown/projects', admin)
+ expect(response.status).to eq(404)
+ end
+
+ it 'should not return a group not attached to user1' do
+ get api("/groups/#{group2.path}/projects", user1)
+ expect(response.status).to eq(403)
+ end
+ end
+ end
+
describe "POST /groups" do
context "when authenticated as user without group permissions" do
it "should not create group" do
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index aff109a9424..667f0dbea5c 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -47,7 +47,7 @@ describe API::API, api: true do
name: 'Foo',
color: '#FFAA'
expect(response.status).to eq(400)
- expect(json_response['message']['color']).to eq(['is invalid'])
+ expect(json_response['message']['color']).to eq(['must be a valid color code'])
end
it 'should return 400 for too long color code' do
@@ -55,7 +55,7 @@ describe API::API, api: true do
name: 'Foo',
color: '#FFAAFFFF'
expect(response.status).to eq(400)
- expect(json_response['message']['color']).to eq(['is invalid'])
+ expect(json_response['message']['color']).to eq(['must be a valid color code'])
end
it 'should return 400 for invalid name' do
@@ -151,12 +151,12 @@ describe API::API, api: true do
expect(json_response['message']['title']).to eq(['is invalid'])
end
- it 'should return 400 for invalid name' do
+ it 'should return 400 when color code is too short' do
put api("/projects/#{project.id}/labels", user),
name: 'label1',
color: '#FF'
expect(response.status).to eq(400)
- expect(json_response['message']['color']).to eq(['is invalid'])
+ expect(json_response['message']['color']).to eq(['must be a valid color code'])
end
it 'should return 400 for too long color code' do
@@ -164,7 +164,7 @@ describe API::API, api: true do
name: 'Foo',
color: '#FFAAFFFF'
expect(response.status).to eq(400)
- expect(json_response['message']['color']).to eq(['is invalid'])
+ expect(json_response['message']['color']).to eq(['must be a valid color code'])
end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index a68c7b1e461..e194eb93cf4 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -6,7 +6,7 @@ describe API::API, api: true do
let(:user) { create(:user) }
let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) }
- let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.seconds) }
+ let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) }
let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds) }
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
@@ -131,6 +131,23 @@ describe API::API, api: true do
end
end
+ describe 'GET /projects/:id/merge_request/:merge_request_id/commits' do
+ context 'valid merge request' do
+ before { get api("/projects/#{project.id}/merge_request/#{merge_request.id}/commits", user) }
+ let(:commit) { merge_request.commits.first }
+
+ it { expect(response.status).to eq 200 }
+ it { expect(json_response.size).to eq(merge_request.commits.size) }
+ it { expect(json_response.first['id']).to eq(commit.id) }
+ it { expect(json_response.first['title']).to eq(commit.title) }
+ end
+
+ it 'returns a 404 when merge_request_id not found' do
+ get api("/projects/#{project.id}/merge_request/999/commits", user)
+ expect(response.status).to eq(404)
+ end
+ end
+
describe 'GET /projects/:id/merge_request/:merge_request_id/changes' do
it 'should return the change information of the merge_request' do
get api("/projects/#{project.id}/merge_request/#{merge_request.id}/changes", user)
@@ -303,19 +320,21 @@ describe API::API, api: true do
end
describe "PUT /projects/:id/merge_request/:merge_request_id/merge" do
+ let(:ci_commit) { create(:ci_commit_without_jobs) }
+
it "should return merge_request in case of success" do
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
expect(response.status).to eq(200)
end
- it "should return 405 if branch can't be merged" do
+ it "should return 406 if branch can't be merged" do
allow_any_instance_of(MergeRequest).
to receive(:can_be_merged?).and_return(false)
put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user)
- expect(response.status).to eq(405)
+ expect(response.status).to eq(406)
expect(json_response['message']).to eq('Branch cannot be merged')
end
@@ -340,6 +359,17 @@ describe API::API, api: true do
expect(response.status).to eq(401)
expect(json_response['message']).to eq('401 Unauthorized')
end
+
+ it "enables merge when build succeeds if the ci is active" do
+ allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit)
+ allow(ci_commit).to receive(:active?).and_return(true)
+
+ put api("/projects/#{project.id}/merge_request/#{merge_request.id}/merge", user), merge_when_build_succeeds: true
+
+ expect(response.status).to eq(200)
+ expect(json_response['title']).to eq('Test')
+ expect(json_response['merge_when_build_succeeds']).to eq(true)
+ end
end
describe "PUT /projects/:id/merge_request/:merge_request_id" do
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 606b226ad77..142b637d291 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -1,11 +1,17 @@
require 'spec_helper'
-describe API::API, 'ProjectHooks', api: true do
+describe API::API, 'ProjectHooks', api: true do
include ApiHelpers
let(:user) { create(:user) }
let(:user3) { create(:user) }
let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
- let!(:hook) { create(:project_hook, project: project, url: "http://example.com", push_events: true, merge_requests_events: true, tag_push_events: true, issues_events: true, note_events: true, enable_ssl_verification: true) }
+ let!(:hook) do
+ create(:project_hook,
+ project: project, url: "http://example.com",
+ push_events: true, merge_requests_events: true, tag_push_events: true,
+ issues_events: true, note_events: true, build_events: true,
+ enable_ssl_verification: true)
+ end
before do
project.team << [user, :master]
@@ -26,6 +32,7 @@ describe API::API, 'ProjectHooks', api: true do
expect(json_response.first['merge_requests_events']).to eq(true)
expect(json_response.first['tag_push_events']).to eq(true)
expect(json_response.first['note_events']).to eq(true)
+ expect(json_response.first['build_events']).to eq(true)
expect(json_response.first['enable_ssl_verification']).to eq(true)
end
end
@@ -83,6 +90,7 @@ describe API::API, 'ProjectHooks', api: true do
expect(json_response['merge_requests_events']).to eq(false)
expect(json_response['tag_push_events']).to eq(false)
expect(json_response['note_events']).to eq(false)
+ expect(json_response['build_events']).to eq(false)
expect(json_response['enable_ssl_verification']).to eq(true)
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 9fc294118ae..01d2ec79482 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -65,6 +65,22 @@ describe API::API, api: true do
expect(json_response.first.keys).to include('tag_list')
end
+ it 'should include open_issues_count' do
+ get api('/projects', user)
+ expect(response.status).to eq 200
+ expect(json_response).to be_an Array
+ expect(json_response.first.keys).to include('open_issues_count')
+ end
+
+ it 'should not include open_issues_count' do
+ project.update_attributes( { issues_enabled: false } )
+
+ get api('/projects', user)
+ expect(response.status).to eq 200
+ expect(json_response).to be_an Array
+ expect(json_response.first.keys).not_to include('open_issues_count')
+ end
+
context 'and using search' do
it 'should return searched project' do
get api('/projects', user), { search: project.name }
@@ -86,18 +102,6 @@ describe API::API, api: true do
expect(json_response).to be_an Array
expect(json_response.first['id']).to eq(project3.id)
end
-
- it 'returns projects in the correct order when ci_enabled_first parameter is passed' do
- [project, project2, project3].each do |project|
- project.builds_enabled = false
- project.build_missing_services
- end
- project2.builds_enabled = true
- get api('/projects', user), { ci_enabled_first: 'true' }
- expect(response.status).to eq(200)
- expect(json_response).to be_an Array
- expect(json_response.first['id']).to eq(project2.id)
- end
end
end
end
@@ -135,6 +139,25 @@ describe API::API, api: true do
end
end
+ describe 'GET /projects/starred' do
+ before do
+ admin.starred_projects << project
+ admin.save!
+ end
+
+ it 'should return the starred projects' do
+ get api('/projects/all', admin)
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+
+ expect(json_response).to satisfy do |response|
+ response.one? do |entry|
+ entry['name'] == project.name
+ end
+ end
+ end
+ end
+
describe 'POST /projects' do
context 'maximum number of projects reached' do
it 'should not create new project and respond with 403' do
@@ -389,14 +412,30 @@ describe API::API, api: true do
describe 'GET /projects/:id/events' do
before { project_member2 }
- it 'should return a project events' do
- get api("/projects/#{project.id}/events", user)
- expect(response.status).to eq(200)
- json_event = json_response.first
+ context 'valid request' do
+ before do
+ note = create(:note_on_issue, note: 'What an awesome day!', project: project)
+ EventCreateService.new.leave_note(note, note.author)
+ get api("/projects/#{project.id}/events", user)
+ end
+
+ it { expect(response.status).to eq(200) }
+
+ context 'joined event' do
+ let(:json_event) { json_response[1] }
+
+ it { expect(json_event['action_name']).to eq('joined') }
+ it { expect(json_event['project_id'].to_i).to eq(project.id) }
+ it { expect(json_event['author_username']).to eq(user3.username) }
+ it { expect(json_event['author']['name']).to eq(user3.name) }
+ end
- expect(json_event['action_name']).to eq('joined')
- expect(json_event['project_id'].to_i).to eq(project.id)
- expect(json_event['author_username']).to eq(user3.username)
+ context 'comment event' do
+ let(:json_event) { json_response.first }
+
+ it { expect(json_event['action_name']).to eq('commented on') }
+ it { expect(json_event['note']['body']).to eq('What an awesome day!') }
+ end
end
it 'should return a 404 error if not found' do
@@ -451,7 +490,7 @@ describe API::API, api: true do
end
end
- describe 'PUT /projects/:id/snippets/:shippet_id' do
+ describe 'PUT /projects/:id/snippets/:snippet_id' do
it 'should update an existing project snippet' do
put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
code: 'updated code'
@@ -726,6 +765,18 @@ describe API::API, api: true do
end
end
+ it 'should update visibility_level from public to private' do
+ project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })
+
+ project_param = { public: false }
+ put api("/projects/#{project3.id}", user), project_param
+ expect(response.status).to eq(200)
+ project_param.each_pair do |k, v|
+ expect(json_response[k.to_s]).to eq(v)
+ end
+ expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+
it 'should not update name to existing name' do
project_param = { name: project3.name }
put api("/projects/#{project.id}", user), project_param
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index b180d2fec77..fed9ae1949b 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -29,7 +29,7 @@ describe API::API, api: true do
if required_attributes.empty?
expected_code = 200
else
- attrs.delete(required_attributes.shuffle.first)
+ attrs.delete(required_attributes.sample)
expected_code = 400
end
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index cc9a5f47582..17f2643fd45 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -28,10 +28,10 @@ describe API::API, api: true do
before do
release = project.releases.find_or_initialize_by(tag: tag_name)
release.update_attributes(description: description)
- get api("/projects/#{project.id}/repository/tags", user)
end
it "should return an array of project tags with release info" do
+ get api("/projects/#{project.id}/repository/tags", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.first['name']).to eq(tag_name)
@@ -119,17 +119,78 @@ describe API::API, api: true do
end
end
- describe 'PUT /projects/:id/repository/:tag/release' do
+ describe 'POST /projects/:id/repository/tags/:tag_name/release' do
let(:tag_name) { project.repository.tag_names.first }
let(:description) { 'Awesome release!' }
it 'should create description for existing git tag' do
- put api("/projects/#{project.id}/repository/#{tag_name}/release", user),
+ post api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user),
description: description
- expect(response.status).to eq(200)
- expect(json_response['tag']).to eq(tag_name)
+ expect(response.status).to eq(201)
+ expect(json_response['tag_name']).to eq(tag_name)
expect(json_response['description']).to eq(description)
end
+
+ it 'should return 404 if the tag does not exist' do
+ post api("/projects/#{project.id}/repository/tags/foobar/release", user),
+ description: description
+
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('Tag does not exist')
+ end
+
+ context 'on tag with existing release' do
+ before do
+ release = project.releases.find_or_initialize_by(tag: tag_name)
+ release.update_attributes(description: description)
+ end
+
+ it 'should return 409 if there is already a release' do
+ post api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user),
+ description: description
+
+ expect(response.status).to eq(409)
+ expect(json_response['message']).to eq('Release already exists')
+ end
+ end
+ end
+
+ describe 'PUT id/repository/tags/:tag_name/release' do
+ let(:tag_name) { project.repository.tag_names.first }
+ let(:description) { 'Awesome release!' }
+ let(:new_description) { 'The best release!' }
+
+ context 'on tag with existing release' do
+ before do
+ release = project.releases.find_or_initialize_by(tag: tag_name)
+ release.update_attributes(description: description)
+ end
+
+ it 'should update the release description' do
+ put api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user),
+ description: new_description
+
+ expect(response.status).to eq(200)
+ expect(json_response['tag_name']).to eq(tag_name)
+ expect(json_response['description']).to eq(new_description)
+ end
+ end
+
+ it 'should return 404 if the tag does not exist' do
+ put api("/projects/#{project.id}/repository/tags/foobar/release", user),
+ description: new_description
+
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('Tag does not exist')
+ end
+
+ it 'should return 404 if the release does not exist' do
+ put api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user),
+ description: new_description
+
+ expect(response.status).to eq(404)
+ expect(json_response['message']).to eq('Release does not exist')
+ end
end
end
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
new file mode 100644
index 00000000000..314bd7ddc59
--- /dev/null
+++ b/spec/requests/api/triggers_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe API::API do
+ include ApiHelpers
+
+ describe 'POST /projects/:project_id/trigger' do
+ let!(:trigger_token) { 'secure token' }
+ let!(:project) { FactoryGirl.create(:project) }
+ let!(:project2) { FactoryGirl.create(:empty_project) }
+ let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
+ let(:options) do
+ {
+ token: trigger_token
+ }
+ end
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
+ context 'Handles errors' do
+ it 'should return bad request if token is missing' do
+ post api("/projects/#{project.id}/trigger/builds"), ref: 'master'
+ expect(response.status).to eq(400)
+ end
+
+ it 'should return not found if project is not found' do
+ post api('/projects/0/trigger/builds'), options.merge(ref: 'master')
+ expect(response.status).to eq(404)
+ end
+
+ it 'should return unauthorized if token is for different project' do
+ post api("/projects/#{project2.id}/trigger/builds"), options.merge(ref: 'master')
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'Have a commit' do
+ let(:commit) { project.ci_commits.last }
+
+ it 'should create builds' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'master')
+ expect(response.status).to eq(201)
+ commit.builds.reload
+ expect(commit.builds.size).to eq(2)
+ end
+
+ it 'should return bad request with no builds created if there\'s no commit for that ref' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'other-branch')
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('No builds created')
+ end
+
+ context 'Validates variables' do
+ let(:variables) do
+ { 'TRIGGER_KEY' => 'TRIGGER_VALUE' }
+ end
+
+ it 'should validate variables to be a hash' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(variables: 'value', ref: 'master')
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('variables needs to be a hash')
+ end
+
+ it 'should validate variables needs to be a map of key-valued strings' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(variables: { key: %w(1 2) }, ref: 'master')
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('variables needs to be a map of key-valued strings')
+ end
+
+ it 'create trigger request with variables' do
+ post api("/projects/#{project.id}/trigger/builds"), options.merge(variables: variables, ref: 'master')
+ expect(response.status).to eq(201)
+ commit.builds.reload
+ expect(commit.builds.first.trigger_request.variables).to eq(variables)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index a9ef2fe5885..2f609c63330 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -153,7 +153,7 @@ describe API::API, api: true do
expect(json_response['message']['projects_limit']).
to eq(['must be greater than or equal to 0'])
expect(json_response['message']['username']).
- to eq([Gitlab::Regex.send(:namespace_regex_message)])
+ to eq([Gitlab::Regex.namespace_regex_message])
end
it "shouldn't available for non admin users" do
@@ -296,7 +296,7 @@ describe API::API, api: true do
expect(json_response['message']['projects_limit']).
to eq(['must be greater than or equal to 0'])
expect(json_response['message']['username']).
- to eq([Gitlab::Regex.send(:namespace_regex_message)])
+ to eq([Gitlab::Regex.namespace_regex_message])
end
context "with existing user" do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index c2be045099d..c27e87c4acc 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -4,8 +4,7 @@ describe Ci::API::API do
include ApiHelpers
let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) }
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { project.gl_project }
+ let(:project) { FactoryGirl.create(:empty_project) }
before do
stub_ci_commit_to_return_yaml_file
@@ -13,16 +12,15 @@ describe Ci::API::API do
describe "Builds API for runners" do
let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
- let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") }
- let(:shared_gl_project) { shared_project.gl_project }
+ let(:shared_project) { FactoryGirl.create(:empty_project, name: "SharedProject") }
before do
- FactoryGirl.create :ci_runner_project, project_id: project.id, runner_id: runner.id
+ FactoryGirl.create :ci_runner_project, project: project, runner: runner
end
describe "POST /builds/register" do
it "should start a build" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil)
build = commit.builds.first
@@ -40,7 +38,7 @@ describe Ci::API::API do
end
it "should return 404 error if no builds for specific runner" do
- commit = FactoryGirl.create(:ci_commit, gl_project: shared_gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: shared_project)
FactoryGirl.create(:ci_build, commit: commit, status: 'pending')
post ci_api("/builds/register"), token: runner.token
@@ -49,7 +47,7 @@ describe Ci::API::API do
end
it "should return 404 error if no builds for shared runner" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
FactoryGirl.create(:ci_build, commit: commit, status: 'pending')
post ci_api("/builds/register"), token: shared_runner.token
@@ -58,7 +56,7 @@ describe Ci::API::API do
end
it "returns options" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil)
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
@@ -68,7 +66,7 @@ describe Ci::API::API do
end
it "returns variables" do
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil)
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
@@ -85,7 +83,7 @@ describe Ci::API::API do
it "returns variables for triggers" do
trigger = FactoryGirl.create(:ci_trigger, project: project)
- commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
+ commit = FactoryGirl.create(:ci_commit, project: project)
trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger)
commit.create_builds('master', false, nil, trigger_request)
@@ -106,7 +104,7 @@ describe Ci::API::API do
end
describe "PUT /builds/:id" do
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project)}
+ let(:commit) { FactoryGirl.create(:ci_commit, project: project)}
let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
it "should update a running build" do
@@ -126,14 +124,14 @@ describe Ci::API::API do
context "Artifacts" 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') }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
+ let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) }
let(:authorize_url) { ci_api("/builds/#{build.id}/artifacts/authorize") }
let(:post_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:get_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:headers) { { "GitLab-Workhorse" => "1.0" } }
- let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.project.token) }
+ let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token) }
describe "POST /builds/:id/artifacts/authorize" do
context "should authorize posting artifact to running build" do
@@ -142,7 +140,7 @@ describe Ci::API::API do
end
it "using token as parameter" do
- post authorize_url, { token: build.project.token }, headers
+ post authorize_url, { token: build.token }, headers
expect(response.status).to eq(200)
expect(json_response["TempPath"]).to_not be_nil
end
@@ -161,7 +159,7 @@ describe Ci::API::API do
it "using token as parameter" do
stub_application_setting(max_artifacts_size: 0)
- post authorize_url, { token: build.project.token, filesize: 100 }, headers
+ post authorize_url, { token: build.token, filesize: 100 }, headers
expect(response.status).to eq(413)
end
@@ -241,7 +239,7 @@ describe Ci::API::API do
end
it do
- post post_url, { token: build.project.token }, {}
+ post post_url, { token: build.token }, {}
expect(response.status).to eq(403)
end
end
@@ -281,12 +279,12 @@ describe Ci::API::API do
describe "DELETE /builds/:id/artifacts" do
before do
build.run!
- post delete_url, token: build.project.token, file: file_upload
+ post delete_url, token: build.token, file: file_upload
end
it "should delete artifact build" do
build.success
- delete delete_url, token: build.project.token
+ delete delete_url, token: build.token
expect(response.status).to eq(200)
end
end
@@ -298,12 +296,12 @@ describe Ci::API::API do
it "should download artifact" do
build.update_attributes(artifacts_file: file_upload)
- get get_url, token: build.project.token
+ get get_url, token: build.token
expect(response.status).to eq(200)
end
it "should fail to download if no artifact uploaded" do
- get get_url, token: build.project.token
+ get get_url, token: build.token
expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb
deleted file mode 100644
index aa51ba95bca..00000000000
--- a/spec/requests/ci/api/commits_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'spec_helper'
-
-describe Ci::API::API, 'Commits' do
- include ApiHelpers
-
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { project.gl_project }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
-
- let(:options) do
- {
- project_token: project.token,
- project_id: project.id
- }
- end
-
- describe "GET /commits" do
- before { commit }
-
- it "should return commits per project" do
- get ci_api("/commits"), options
-
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(1)
- expect(json_response.first["project_id"]).to eq(project.id)
- expect(json_response.first["sha"]).to eq(commit.sha)
- end
- end
-
- describe "POST /commits" do
- let(:data) do
- {
- "before" => "95790bf891e76fee5e1747ab589903a6a1f80f22",
- "after" => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
- "ref" => "refs/heads/master",
- "commits" => [
- {
- "id" => "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- "message" => "Update Catalan translation to e38cb41.",
- "timestamp" => "2011-12-12T14:27:31+02:00",
- "url" => "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
- "author" => {
- "name" => "Jordi Mallach",
- "email" => "jordi@softcatala.org",
- }
- }
- ]
- }
- end
-
- it "should create a build" do
- post ci_api("/commits"), options.merge(data: data)
-
- expect(response.status).to eq(201)
- expect(json_response['sha']).to eq("da1560886d4f094c3e6c9ef40349f7d38b5d27d7")
- end
-
- it "should return 400 error if no data passed" do
- post ci_api("/commits"), options
-
- expect(response.status).to eq(400)
- expect(json_response['message']).to eq("400 (Bad request) \"data\" not given")
- end
- end
-end
diff --git a/spec/requests/ci/api/projects_spec.rb b/spec/requests/ci/api/projects_spec.rb
deleted file mode 100644
index 893fd168d3e..00000000000
--- a/spec/requests/ci/api/projects_spec.rb
+++ /dev/null
@@ -1,232 +0,0 @@
-require 'spec_helper'
-
-describe Ci::API::API do
- include ApiHelpers
-
- let(:gitlab_url) { GitlabCi.config.gitlab_ci.url }
- let(:user) { create(:user) }
- let(:private_token) { user.private_token }
-
- let(:options) do
- {
- private_token: private_token,
- url: gitlab_url
- }
- end
-
- before do
- stub_gitlab_calls
- end
-
- context "requests for scoped projects" do
- # NOTE: These ids are tied to the actual projects on demo.gitlab.com
- describe "GET /projects" do
- let!(:project1) { FactoryGirl.create(:ci_project) }
- let!(:project2) { FactoryGirl.create(:ci_project) }
-
- before do
- project1.gl_project.team << [user, :developer]
- project2.gl_project.team << [user, :developer]
- end
-
- it "should return all projects on the CI instance" do
- get ci_api("/projects"), options
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(2)
- expect(json_response.first["id"]).to eq(project1.id)
- expect(json_response.last["id"]).to eq(project2.id)
- end
- end
-
- describe "GET /projects/owned" do
- let!(:gl_project1) {FactoryGirl.create(:empty_project, namespace: user.namespace)}
- let!(:gl_project2) {FactoryGirl.create(:empty_project, namespace: user.namespace)}
- let!(:project1) { gl_project1.ensure_gitlab_ci_project }
- let!(:project2) { gl_project2.ensure_gitlab_ci_project }
-
- before do
- project1.gl_project.team << [user, :developer]
- project2.gl_project.team << [user, :developer]
- end
-
- it "should return all projects on the CI instance" do
- get ci_api("/projects/owned"), options
-
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(2)
- end
- end
- end
-
- describe "POST /projects/:project_id/webhooks" do
- let!(:project) { FactoryGirl.create(:ci_project) }
-
- context "Valid Webhook URL" do
- let!(:webhook) { { web_hook: "http://example.com/sth/1/ala_ma_kota" } }
-
- before do
- options.merge!(webhook)
- end
-
- it "should create webhook for specified project" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(201)
- expect(json_response["url"]).to eq(webhook[:web_hook])
- end
-
- it "fails to create webhook for non existsing project" do
- post ci_api("/projects/non-existant-id/webhooks"), options
- expect(response.status).to eq(404)
- end
-
- it "non-manager is not authorized" do
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(401)
- end
- end
-
- context "Invalid Webhook URL" do
- let!(:webhook) { { web_hook: "ala_ma_kota" } }
-
- before do
- options.merge!(webhook)
- end
-
- it "fails to create webhook for not valid url" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(400)
- end
- end
-
- context "Missed web_hook parameter" do
- it "fails to create webhook for not provided url" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/webhooks"), options
- expect(response.status).to eq(400)
- end
- end
- end
-
- describe "GET /projects/:id" do
- let!(:project) { FactoryGirl.create(:ci_project) }
-
- before do
- project.gl_project.team << [user, :developer]
- end
-
- context "with an existing project" do
- it "should retrieve the project info" do
- get ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(200)
- expect(json_response['id']).to eq(project.id)
- end
- end
-
- context "with a non-existing project" do
- it "should return 404 error if project not found" do
- get ci_api("/projects/non_existent_id"), options
- expect(response.status).to eq(404)
- end
- end
- end
-
- describe "PUT /projects/:id" do
- let!(:project) { FactoryGirl.create(:ci_project) }
- let!(:project_info) { { default_ref: "develop" } }
-
- before do
- options.merge!(project_info)
- end
-
- it "should update a specific project's information" do
- project.gl_project.team << [user, :master]
- put ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(200)
- expect(json_response["default_ref"]).to eq(project_info[:default_ref])
- end
-
- it "fails to update a non-existing project" do
- put ci_api("/projects/non-existant-id"), options
- expect(response.status).to eq(404)
- end
-
- it "non-manager is not authorized" do
- put ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(401)
- end
- end
-
- describe "DELETE /projects/:id" do
- let!(:project) { FactoryGirl.create(:ci_project) }
-
- it "should delete a specific project" do
- project.gl_project.team << [user, :master]
- delete ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(200)
- expect { project.reload }.
- to raise_error(ActiveRecord::RecordNotFound)
- end
-
- it "non-manager is not authorized" do
- delete ci_api("/projects/#{project.id}"), options
- expect(response.status).to eq(401)
- end
-
- it "is getting not found error" do
- delete ci_api("/projects/not-existing_id"), options
- expect(response.status).to eq(404)
- end
- end
-
- describe "POST /projects/:id/runners/:id" do
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:runner) { FactoryGirl.create(:ci_runner) }
-
- it "should add the project to the runner" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(201)
-
- project.reload
- expect(project.runners.first.id).to eq(runner.id)
- end
-
- it "should fail if it tries to link a non-existing project or runner" do
- post ci_api("/projects/#{project.id}/runners/non-existing"), options
- expect(response.status).to eq(404)
-
- post ci_api("/projects/non-existing/runners/#{runner.id}"), options
- expect(response.status).to eq(404)
- end
-
- it "non-manager is not authorized" do
- allow_any_instance_of(User).to receive(:can_manage_project?).and_return(false)
- post ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(401)
- end
- end
-
- describe "DELETE /projects/:id/runners/:id" do
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:runner) { FactoryGirl.create(:ci_runner) }
-
- it "should remove the project from the runner" do
- project.gl_project.team << [user, :master]
- post ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
-
- expect(project.runners).to be_present
- delete ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(200)
-
- project.reload
- expect(project.runners).to be_empty
- end
-
- it "non-manager is not authorized" do
- delete ci_api("/projects/#{project.id}/runners/#{runner.id}"), options
- expect(response.status).to eq(401)
- end
- end
-end
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 11dc089e1f5..567da013e6f 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -4,57 +4,38 @@ describe Ci::API::API do
include ApiHelpers
include StubGitlabCalls
+ let(:registration_token) { 'abcdefg123456' }
+
before do
stub_gitlab_calls
- end
-
- describe "GET /runners" do
- let(:gitlab_url) { GitlabCi.config.gitlab_ci.url }
- let(:private_token) { create(:user).private_token }
- let(:options) do
- {
- private_token: private_token,
- url: gitlab_url
- }
- end
-
- before do
- 5.times { FactoryGirl.create(:ci_runner) }
- end
-
- it "should retrieve a list of all runners" do
- get ci_api("/runners", nil), options
- expect(response.status).to eq(200)
- expect(json_response.count).to eq(5)
- expect(json_response.last).to have_key("id")
- expect(json_response.last).to have_key("token")
- end
+ stub_application_setting(ensure_runners_registration_token: registration_token)
+ stub_application_setting(runners_registration_token: registration_token)
end
describe "POST /runners/register" do
describe "should create a runner if token provided" do
- before { post ci_api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN }
+ before { post ci_api("/runners/register"), token: registration_token }
it { expect(response.status).to eq(201) }
end
describe "should create a runner with description" do
- before { post ci_api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, description: "server.hostname" }
+ before { post ci_api("/runners/register"), token: registration_token, description: "server.hostname" }
it { expect(response.status).to eq(201) }
it { expect(Ci::Runner.first.description).to eq("server.hostname") }
end
describe "should create a runner with tags" do
- before { post ci_api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, tag_list: "tag1, tag2" }
+ before { post ci_api("/runners/register"), token: registration_token, tag_list: "tag1, tag2" }
it { expect(response.status).to eq(201) }
it { expect(Ci::Runner.first.tag_list.sort).to eq(["tag1", "tag2"]) }
end
describe "should create a runner if project token provided" do
- let(:project) { FactoryGirl.create(:ci_project) }
- before { post ci_api("/runners/register"), token: project.token }
+ let(:project) { FactoryGirl.create(:empty_project) }
+ before { post ci_api("/runners/register"), token: project.runners_token }
it { expect(response.status).to eq(201) }
it { expect(project.runners.size).to eq(1) }
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index a2b436d5811..0ef03f9371b 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -5,9 +5,8 @@ describe Ci::API::API do
describe 'POST /projects/:project_id/refs/:ref/trigger' do
let!(:trigger_token) { 'secure token' }
- let!(:gl_project) { FactoryGirl.create(:project) }
- let!(:project) { gl_project.ensure_gitlab_ci_project }
- let!(:project2) { FactoryGirl.create(:ci_project) }
+ let!(:project) { FactoryGirl.create(:project, ci_id: 10) }
+ let!(:project2) { FactoryGirl.create(:empty_project, ci_id: 11) }
let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
let(:options) do
{
@@ -21,7 +20,7 @@ describe Ci::API::API do
context 'Handles errors' do
it 'should return bad request if token is missing' do
- post ci_api("/projects/#{project.id}/refs/master/trigger")
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger")
expect(response.status).to eq(400)
end
@@ -31,23 +30,23 @@ describe Ci::API::API do
end
it 'should return unauthorized if token is for different project' do
- post ci_api("/projects/#{project2.id}/refs/master/trigger"), options
+ post ci_api("/projects/#{project2.ci_id}/refs/master/trigger"), options
expect(response.status).to eq(401)
end
end
context 'Have a commit' do
- let(:commit) { project.commits.last }
+ let(:commit) { project.ci_commits.last }
it 'should create builds' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options
expect(response.status).to eq(201)
commit.builds.reload
expect(commit.builds.size).to eq(2)
end
it 'should return bad request with no builds created if there\'s no commit for that ref' do
- post ci_api("/projects/#{project.id}/refs/other-branch/trigger"), options
+ post ci_api("/projects/#{project.ci_id}/refs/other-branch/trigger"), options
expect(response.status).to eq(400)
expect(json_response['message']).to eq('No builds created')
end
@@ -58,19 +57,19 @@ describe Ci::API::API do
end
it 'should validate variables to be a hash' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: 'value')
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: 'value')
expect(response.status).to eq(400)
expect(json_response['message']).to eq('variables needs to be a hash')
end
it 'should validate variables needs to be a map of key-valued strings' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: { key: %w(1 2) })
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: { key: %w(1 2) })
expect(response.status).to eq(400)
expect(json_response['message']).to eq('variables needs to be a map of key-valued strings')
end
it 'create trigger request with variables' do
- post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables)
+ post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: variables)
expect(response.status).to eq(201)
commit.builds.reload
expect(commit.builds.first.trigger_request.variables).to eq(variables)
diff --git a/spec/services/archive_repository_service_spec.rb b/spec/services/archive_repository_service_spec.rb
index f7a36cd9670..bd871605c66 100644
--- a/spec/services/archive_repository_service_spec.rb
+++ b/spec/services/archive_repository_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ArchiveRepositoryService do
+describe ArchiveRepositoryService, services: true do
let(:project) { create(:project) }
subject { ArchiveRepositoryService.new(project, "master", "zip") }
diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb
deleted file mode 100644
index e0ede1d58b7..00000000000
--- a/spec/services/ci/create_commit_service_spec.rb
+++ /dev/null
@@ -1,172 +0,0 @@
-require 'spec_helper'
-
-module Ci
- describe CreateCommitService do
- let(:service) { CreateCommitService.new }
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:user) { nil }
-
- before do
- stub_ci_commit_to_return_yaml_file
- end
-
- describe :execute do
- context 'valid params' do
- let(:commit) do
- service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: [ { message: "Message" } ]
- )
- end
-
- it { expect(commit).to be_kind_of(Commit) }
- it { expect(commit).to be_valid }
- it { expect(commit).to be_persisted }
- it { expect(commit).to eq(project.commits.last) }
- it { expect(commit.builds.first).to be_kind_of(Build) }
- end
-
- context "skip tag if there is no build for it" do
- it "creates commit if there is appropriate job" do
- result = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: [ { message: "Message" } ]
- )
- expect(result).to be_persisted
- end
-
- it "creates commit if there is no appropriate job but deploy job has right ref setting" do
- config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
- stub_ci_commit_yaml_file(config)
-
- result = service.execute(project, user,
- ref: 'refs/heads/0_1',
- before: '00000000',
- after: '31das312',
- commits: [ { message: "Message" } ]
- )
- expect(result).to be_persisted
- end
- end
-
- it 'skips commits without .gitlab-ci.yml' do
- stub_ci_commit_yaml_file(nil)
- result = service.execute(project, user,
- ref: 'refs/heads/0_1',
- before: '00000000',
- after: '31das312',
- commits: [ { message: 'Message' } ]
- )
- expect(result).to be_persisted
- expect(result.builds.any?).to be_falsey
- expect(result.status).to eq('skipped')
- expect(result.yaml_errors).to be_nil
- end
-
- it 'skips commits if yaml is invalid' do
- message = 'message'
- allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
- stub_ci_commit_yaml_file('invalid: file: file')
- commits = [{ message: message }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.any?).to be false
- expect(commit.status).to eq('failed')
- expect(commit.yaml_errors).to_not be_nil
- end
-
- describe :ci_skip? do
- let(:message) { "some message[ci skip]" }
-
- before do
- allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
- end
-
- it "skips builds creation if there is [ci skip] tag in commit message" do
- commits = [{ message: message }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.any?).to be false
- expect(commit.status).to eq("skipped")
- end
-
- it "does not skips builds creation if there is no [ci skip] tag in commit message" do
- allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
-
- commits = [{ message: "some message" }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(commit.builds.first.name).to eq("staging")
- end
-
- it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
- stub_ci_commit_yaml_file('invalid: file: fiile')
- commits = [{ message: message }]
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.any?).to be false
- expect(commit.status).to eq("skipped")
- expect(commit.yaml_errors).to be_nil
- end
- end
-
- it "skips build creation if there are already builds" do
- allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
-
- commits = [{ message: "message" }]
- commit = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.count(:all)).to eq(2)
-
- commit = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(commit.builds.count(:all)).to eq(2)
- end
-
- it "creates commit with failed status if yaml is invalid" do
- stub_ci_commit_yaml_file('invalid: file')
-
- commits = [{ message: "some message" }]
-
- commit = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(commit.status).to eq("failed")
- expect(commit.builds.any?).to be false
- end
- end
- end
-end
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index 2ef4bb50a57..dbdc5370bd8 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -1,9 +1,8 @@
require 'spec_helper'
-describe Ci::CreateTriggerRequestService do
+describe Ci::CreateTriggerRequestService, services: true do
let(:service) { Ci::CreateTriggerRequestService.new }
- let(:gl_project) { create(:project) }
- let(:project) { gl_project.ensure_gitlab_ci_project }
+ let(:project) { create(:project) }
let(:trigger) { create(:ci_trigger, project: project) }
before do
@@ -29,7 +28,7 @@ describe Ci::CreateTriggerRequestService do
before do
stub_ci_commit_yaml_file('{}')
- FactoryGirl.create :ci_commit, gl_project: gl_project
+ FactoryGirl.create :ci_commit, project: project
end
it { expect(subject).to be_nil }
diff --git a/spec/services/ci/event_service_spec.rb b/spec/services/ci/event_service_spec.rb
deleted file mode 100644
index 1264e17ff5e..00000000000
--- a/spec/services/ci/event_service_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-
-describe Ci::EventService do
- let(:project) { FactoryGirl.create :ci_project }
- let(:user) { double(username: "root", id: 1) }
-
- before do
- Event.destroy_all
- end
-
- describe :remove_project do
- it "creates event" do
- Ci::EventService.new.remove_project(user, project)
-
- expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been removed by root")
- end
- end
-
- describe :create_project do
- it "creates event" do
- Ci::EventService.new.create_project(user, project)
-
- expect(Ci::Event.admin.last.description).to eq("Project \"#{project.name_with_namespace}\" has been created by root")
- end
- end
-
- describe :change_project_settings do
- it "creates event" do
- Ci::EventService.new.change_project_settings(user, project)
-
- expect(Ci::Event.last.description).to eq("User \"root\" updated projects settings")
- end
- end
-end
diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb
index cda7d0c4a51..870861ad20a 100644
--- a/spec/services/ci/image_for_build_service_spec.rb
+++ b/spec/services/ci/image_for_build_service_spec.rb
@@ -1,18 +1,18 @@
require 'spec_helper'
module Ci
- describe ImageForBuildService do
+ describe ImageForBuildService, services: true do
let(:service) { ImageForBuildService.new }
- let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { FactoryGirl.create(:project, gitlab_ci_project: project) }
- let(:commit_sha) { gl_project.commit('master').sha }
- let(:commit) { gl_project.ensure_ci_commit(commit_sha) }
+ let(:project) { FactoryGirl.create(:empty_project) }
+ let(:commit_sha) { '01234567890123456789' }
+ let(:commit) { project.ensure_ci_commit(commit_sha) }
let(:build) { FactoryGirl.create(:ci_build, commit: commit) }
describe :execute do
before { build }
context 'branch name' do
+ before { allow(project).to receive(:commit).and_return(OpenStruct.new(sha: commit_sha)) }
before { build.run! }
let(:image) { service.execute(project, ref: 'master') }
diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb
index b370dfbe113..e81f9e757ac 100644
--- a/spec/services/ci/register_build_service_spec.rb
+++ b/spec/services/ci/register_build_service_spec.rb
@@ -1,16 +1,16 @@
require 'spec_helper'
module Ci
- describe RegisterBuildService do
+ describe RegisterBuildService, services: true do
let!(:service) { RegisterBuildService.new }
- let!(:gl_project) { FactoryGirl.create :empty_project }
- let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+ let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
+ let!(:commit) { FactoryGirl.create :ci_commit, project: project }
let!(:pending_build) { FactoryGirl.create :ci_build, commit: commit }
let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) }
let!(:specific_runner) { FactoryGirl.create(:ci_runner, is_shared: false) }
before do
- specific_runner.assign_to(gl_project.ensure_gitlab_ci_project)
+ specific_runner.assign_to(project)
end
describe :execute do
@@ -47,7 +47,7 @@ module Ci
context 'allow shared runners' do
before do
- gl_project.gitlab_ci_project.update(shared_runners_enabled: true)
+ project.update(shared_runners_enabled: true)
end
context 'shared runner' do
@@ -71,7 +71,7 @@ module Ci
context 'disallow shared runners' do
before do
- gl_project.gitlab_ci_project.update(shared_runners_enabled: false)
+ project.update(shared_runners_enabled: false)
end
context 'shared runner' do
diff --git a/spec/services/ci/web_hook_service_spec.rb b/spec/services/ci/web_hook_service_spec.rb
deleted file mode 100644
index aa48fcbcbfd..00000000000
--- a/spec/services/ci/web_hook_service_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'spec_helper'
-
-describe Ci::WebHookService do
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
- let(:build) { FactoryGirl.create :ci_build, commit: commit }
- let(:hook) { FactoryGirl.create :ci_web_hook, project: project }
-
- describe :execute do
- it "should execute successfully" do
- stub_request(:post, hook.url).to_return(status: 200)
- expect(Ci::WebHookService.new.build_end(build)).to be_truthy
- end
- end
-
- context 'build_data' do
- it "contains all needed fields" do
- expect(build_data(build)).to include(
- :build_id,
- :project_id,
- :ref,
- :build_status,
- :build_started_at,
- :build_finished_at,
- :before_sha,
- :project_name,
- :gitlab_url,
- :build_name
- )
- end
- end
-
- def build_data(build)
- Ci::WebHookService.new.send :build_data, build
- end
-end
diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb
new file mode 100644
index 00000000000..ea5dcfa068a
--- /dev/null
+++ b/spec/services/create_commit_builds_service_spec.rb
@@ -0,0 +1,175 @@
+require 'spec_helper'
+
+describe CreateCommitBuildsService, services: true do
+ let(:service) { CreateCommitBuildsService.new }
+ let(:project) { FactoryGirl.create(:empty_project) }
+ let(:user) { nil }
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
+ describe :execute do
+ context 'valid params' do
+ let(:commit) do
+ service.execute(project, user,
+ ref: 'refs/heads/master',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: "Message" }]
+ )
+ end
+
+ it { expect(commit).to be_kind_of(Ci::Commit) }
+ it { expect(commit).to be_valid }
+ it { expect(commit).to be_persisted }
+ it { expect(commit).to eq(project.ci_commits.last) }
+ it { expect(commit.builds.first).to be_kind_of(Ci::Build) }
+ end
+
+ context "skip tag if there is no build for it" do
+ it "creates commit if there is appropriate job" do
+ result = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: "Message" }]
+ )
+ expect(result).to be_persisted
+ end
+
+ it "creates commit if there is no appropriate job but deploy job has right ref setting" do
+ config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
+ stub_ci_commit_yaml_file(config)
+
+ result = service.execute(project, user,
+ ref: 'refs/heads/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: "Message" }]
+ )
+ expect(result).to be_persisted
+ end
+ end
+
+ it 'skips creating ci_commit for refs without .gitlab-ci.yml' do
+ stub_ci_commit_yaml_file(nil)
+ result = service.execute(project, user,
+ ref: 'refs/heads/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: [{ message: 'Message' }]
+ )
+ expect(result).to be_falsey
+ expect(Ci::Commit.count).to eq(0)
+ end
+
+ it 'fails commits if yaml is invalid' do
+ message = 'message'
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
+ stub_ci_commit_yaml_file('invalid: file: file')
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit).to be_persisted
+ expect(commit.builds.any?).to be false
+ expect(commit.status).to eq('failed')
+ expect(commit.yaml_errors).to_not be_nil
+ end
+
+ describe :ci_skip? do
+ let(:message) { "some message[ci skip]" }
+
+ before do
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
+ end
+
+ it "skips builds creation if there is [ci skip] tag in commit message" do
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit).to be_persisted
+ expect(commit.builds.any?).to be false
+ expect(commit.status).to eq("skipped")
+ end
+
+ it "does not skips builds creation if there is no [ci skip] tag in commit message" do
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
+
+ commits = [{ message: "some message" }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+
+ expect(commit).to be_persisted
+ expect(commit.builds.first.name).to eq("staging")
+ end
+
+ it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
+ stub_ci_commit_yaml_file('invalid: file: fiile')
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit).to be_persisted
+ expect(commit.builds.any?).to be false
+ expect(commit.status).to eq("skipped")
+ expect(commit.yaml_errors).to be_nil
+ end
+ end
+
+ it "skips build creation if there are already builds" do
+ allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
+
+ commits = [{ message: "message" }]
+ commit = service.execute(project, user,
+ ref: 'refs/heads/master',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit).to be_persisted
+ expect(commit.builds.count(:all)).to eq(2)
+
+ commit = service.execute(project, user,
+ ref: 'refs/heads/master',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+ expect(commit).to be_persisted
+ expect(commit.builds.count(:all)).to eq(2)
+ end
+
+ it "creates commit with failed status if yaml is invalid" do
+ stub_ci_commit_yaml_file('invalid: file')
+
+ commits = [{ message: "some message" }]
+
+ commit = service.execute(project, user,
+ ref: 'refs/tags/0_1',
+ before: '00000000',
+ after: '31das312',
+ commits: commits
+ )
+
+ expect(commit).to be_persisted
+ expect(commit.status).to eq("failed")
+ expect(commit.builds.any?).to be false
+ end
+ end
+end
diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb
new file mode 100644
index 00000000000..61e5ae72f51
--- /dev/null
+++ b/spec/services/create_release_service_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe CreateReleaseService, services: true do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:tag_name) { project.repository.tag_names.first }
+ let(:description) { 'Awesome release!' }
+ let(:service) { CreateReleaseService.new(project, user) }
+
+ it 'creates a new release' do
+ result = service.execute(tag_name, description)
+ expect(result[:status]).to eq(:success)
+ release = project.releases.find_by(tag: tag_name)
+ expect(release).not_to be_nil
+ expect(release.description).to eq(description)
+ end
+
+ it 'raises an error if the tag does not exist' do
+ result = service.execute("foobar", description)
+ expect(result[:status]).to eq(:error)
+ end
+
+ context 'there already exists a release on a tag' do
+ before do
+ service.execute(tag_name, description)
+ end
+
+ it 'raises an error and does not update the release' do
+ result = service.execute(tag_name, 'The best release!')
+ expect(result[:status]).to eq(:error)
+ expect(project.releases.find_by(tag: tag_name).description).to eq(description)
+ end
+ end
+end
diff --git a/spec/services/create_snippet_service_spec.rb b/spec/services/create_snippet_service_spec.rb
index 8edabe9450b..c800dea04fa 100644
--- a/spec/services/create_snippet_service_spec.rb
+++ b/spec/services/create_snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateSnippetService do
+describe CreateSnippetService, services: true do
before do
@user = create :user
@admin = create :user, admin: true
diff --git a/spec/services/destroy_group_service_spec.rb b/spec/services/destroy_group_service_spec.rb
index e28564b3866..afa89b84175 100644
--- a/spec/services/destroy_group_service_spec.rb
+++ b/spec/services/destroy_group_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DestroyGroupService do
+describe DestroyGroupService, services: true do
let!(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:project) { create(:project, namespace: group) }
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index 7756b973ecd..f6dc9d4008f 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe EventCreateService do
+describe EventCreateService, services: true do
let(:service) { EventCreateService.new }
describe 'Issues' do
diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb
new file mode 100644
index 00000000000..2bb9c3b3db3
--- /dev/null
+++ b/spec/services/git_hooks_service_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe GitHooksService, services: true do
+ include RepoHelpers
+
+ let(:user) { create :user }
+ let(:project) { create :project }
+ let(:service) { GitHooksService.new }
+
+ before do
+ @blankrev = Gitlab::Git::BLANK_SHA
+ @oldrev = sample_commit.parent_id
+ @newrev = sample_commit.id
+ @ref = 'refs/heads/feature'
+ @repo_path = project.repository.path_to_repo
+ end
+
+ describe '#execute' do
+
+ context 'when receive hooks were successful' do
+ it 'should call post-receive hook' do
+ hook = double(trigger: true)
+ expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
+
+ expect(service.execute(user, @repo_path, @blankrev, @newrev, @ref) { }).to eq(true)
+ end
+ end
+
+ context 'when pre-receive hook failed' do
+ it 'should not call post-receive hook' do
+ expect(service).to receive(:run_hook).with('pre-receive').and_return(false)
+ expect(service).not_to receive(:run_hook).with('post-receive')
+
+ expect do
+ service.execute(user, @repo_path, @blankrev, @newrev, @ref)
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+ end
+
+ context 'when update hook failed' do
+ it 'should not call post-receive hook' do
+ expect(service).to receive(:run_hook).with('pre-receive').and_return(true)
+ expect(service).to receive(:run_hook).with('update').and_return(false)
+ expect(service).not_to receive(:run_hook).with('post-receive')
+
+ expect do
+ service.execute(user, @repo_path, @blankrev, @newrev, @ref)
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+ end
+
+ end
+end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 17015d29e51..a04c242cf0e 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GitPushService do
+describe GitPushService, services: true do
include RepoHelpers
let(:user) { create :user }
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index eed50c7ebac..b982274c529 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GitTagPushService do
+describe GitTagPushService, services: true do
include RepoHelpers
let(:user) { create :user }
@@ -58,14 +58,14 @@ describe GitTagPushService do
it { is_expected.to include(timestamp: @commit.date.xmlschema) }
it do
is_expected.to include(
- url: [
- Gitlab.config.gitlab.url,
- project.namespace.to_param,
- project.to_param,
- 'commit',
- @commit.id
- ].join('/')
- )
+ url: [
+ Gitlab.config.gitlab.url,
+ project.namespace.to_param,
+ project.to_param,
+ 'commit',
+ @commit.id
+ ].join('/')
+ )
end
context "with a author" do
diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issues/bulk_update_service_spec.rb
index 4c62fbafd73..6a7ea4b2f44 100644
--- a/spec/services/issues/bulk_update_service_spec.rb
+++ b/spec/services/issues/bulk_update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::BulkUpdateService do
+describe Issues::BulkUpdateService, services: true do
let(:issue) { create(:issue, project: @project) }
before do
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index db547ce0d50..3a8daf28f5e 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::CloseService do
+describe Issues::CloseService, services: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:issue) { create(:issue, assignee: user2) }
@@ -14,7 +14,9 @@ describe Issues::CloseService do
describe :execute do
context "valid params" do
before do
- @issue = Issues::CloseService.new(project, user, {}).execute(issue)
+ perform_enqueued_jobs do
+ @issue = Issues::CloseService.new(project, user, {}).execute(issue)
+ end
end
it { expect(@issue).to be_valid }
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 7f1ebcb3198..2148d091a57 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::CreateService do
+describe Issues::CreateService, services: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index f55527ee9a3..87da0e9618b 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::UpdateService do
+describe Issues::UpdateService, services: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
@@ -15,6 +15,17 @@ describe Issues::UpdateService do
end
describe 'execute' do
+ def find_note(starting_with)
+ @issue.notes.find do |note|
+ note && note.note.start_with?(starting_with)
+ end
+ end
+
+ def update_issue(opts)
+ @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
+ @issue.reload
+ end
+
context "valid params" do
before do
opts = {
@@ -25,7 +36,10 @@ describe Issues::UpdateService do
label_ids: [label.id]
}
- @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
+ perform_enqueued_jobs do
+ @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
+ end
+
@issue.reload
end
@@ -44,12 +58,6 @@ describe Issues::UpdateService do
expect(email.subject).to include(issue.title)
end
- def find_note(starting_with)
- @issue.notes.find do |note|
- note && note.note.start_with?(starting_with)
- end
- end
-
it 'should create system note about issue reassign' do
note = find_note('Reassigned to')
@@ -71,5 +79,71 @@ describe Issues::UpdateService do
expect(note.note).to eq 'Title changed from **Old title** to **New title**'
end
end
+
+ context 'when Issue has tasks' do
+ before { update_issue({ description: "- [ ] Task 1\n- [ ] Task 2" }) }
+
+ 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" }) }
+
+ it 'creates system note about task status change' do
+ note1 = find_note('Marked the task **Task 1** as completed')
+ note2 = find_note('Marked the task **Task 2** as completed')
+
+ expect(note1).not_to be_nil
+ expect(note2).not_to be_nil
+ end
+ end
+
+ context 'when tasks are marked as incomplete' do
+ before do
+ update_issue({ description: "- [x] Task 1\n- [X] Task 2" })
+ update_issue({ description: "- [ ] Task 1\n- [ ] Task 2" })
+ end
+
+ it 'creates system note about task status change' do
+ note1 = find_note('Marked the task **Task 1** as incomplete')
+ note2 = find_note('Marked the task **Task 2** as incomplete')
+
+ expect(note1).not_to be_nil
+ expect(note2).not_to be_nil
+ end
+ end
+
+ context 'when tasks position has been modified' do
+ before do
+ update_issue({ description: "- [x] Task 1\n- [X] Task 2" })
+ 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')
+
+ expect(note).to be_nil
+ end
+ end
+
+ context 'when a Task list with a completed item is totally replaced' do
+ before do
+ update_issue({ description: "- [ ] Task 1\n- [X] Task 2" })
+ update_issue({ description: "- [ ] One\n- [ ] Two\n- [ ] Three" })
+ end
+
+ it 'does not create a system note referencing the position the old item' do
+ note = find_note('Marked the task **Two** as incomplete')
+
+ expect(note).to be_nil
+ end
+
+ it 'should not generate a new note at all' do
+ expect do
+ update_issue({ description: "- [ ] One\n- [ ] Two\n- [ ] Three" })
+ end.not_to change { Note.count }
+ end
+ end
+ end
+
end
end
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index b3cbfd4b5b8..50d0c288790 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CloseService do
+describe MergeRequests::CloseService, services: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user2) }
@@ -18,7 +18,9 @@ describe MergeRequests::CloseService do
before do
allow(service).to receive(:execute_hooks)
- @merge_request = service.execute(merge_request)
+ perform_enqueued_jobs do
+ @merge_request = service.execute(merge_request)
+ end
end
it { expect(@merge_request).to be_valid }
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index cc64d69361e..be8f1676eeb 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CreateService do
+describe MergeRequests::CreateService, services: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 7483f51de03..ceb3f97280e 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::MergeService do
+describe MergeRequests::MergeService, services: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user2) }
@@ -13,12 +13,14 @@ describe MergeRequests::MergeService do
describe :execute do
context 'valid params' do
- let(:service) { MergeRequests::MergeService.new(project, user, {}) }
+ let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
before do
allow(service).to receive(:execute_hooks)
- service.execute(merge_request, 'Awesome message')
+ perform_enqueued_jobs do
+ service.execute(merge_request)
+ end
end
it { expect(merge_request).to be_valid }
@@ -37,14 +39,14 @@ describe MergeRequests::MergeService do
end
context "error handling" do
- let(:service) { MergeRequests::MergeService.new(project, user, {}) }
+ let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
it 'saves error if there is an exception' do
allow(service).to receive(:repository).and_raise("error")
allow(service).to receive(:execute_hooks)
- service.execute(merge_request, 'Awesome message')
+ service.execute(merge_request)
expect(merge_request.merge_error).to eq("Something went wrong during merge")
end
diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
new file mode 100644
index 00000000000..449cecaa789
--- /dev/null
+++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
@@ -0,0 +1,84 @@
+require 'spec_helper'
+
+describe MergeRequests::MergeWhenBuildSucceedsService do
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request) }
+
+ let(:mr_merge_if_green_enabled) do
+ create(:merge_request, merge_when_build_succeeds: true, merge_user: user,
+ source_branch: "source_branch", target_branch: project.default_branch,
+ source_project: project, target_project: project, state: "opened")
+ end
+
+ let(:project) { create(:project) }
+ let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) }
+ let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') }
+
+ describe "#execute" do
+ context 'first time enabling' do
+ before do
+ allow(merge_request).to receive(:ci_commit).and_return(ci_commit)
+ service.execute(merge_request)
+ end
+
+ it 'sets the params, merge_user, and flag' do
+ expect(merge_request).to be_valid
+ expect(merge_request.merge_when_build_succeeds).to be_truthy
+ expect(merge_request.merge_params).to eq commit_message: 'Awesome message'
+ expect(merge_request.merge_user).to be user
+ end
+
+ it 'creates a system note' do
+ note = merge_request.notes.last
+ expect(note.note).to match /Enabled an automatic merge when the build for (\w+\/\w+@)?[0-9a-z]{8}/
+ end
+ end
+
+ context 'already approved' do
+ let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, new_key: true) }
+ let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) }
+
+ before do
+ allow(mr_merge_if_green_enabled).to receive(:ci_commit).and_return(ci_commit)
+ allow(mr_merge_if_green_enabled).to receive(:mergeable?).and_return(true)
+ allow(ci_commit).to receive(:success?).and_return(true)
+ end
+
+ it 'updates the merge params' do
+ expect(SystemNoteService).not_to receive(:merge_when_build_succeeds)
+
+ service.execute(mr_merge_if_green_enabled)
+ expect(mr_merge_if_green_enabled.merge_params).to have_key(:new_key)
+ end
+ end
+ end
+
+ describe "#trigger" do
+ let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") }
+
+ it "merges all merge requests with merge when build succeeds enabled" do
+ allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit)
+ allow(ci_commit).to receive(:success?).and_return(true)
+
+ expect(MergeWorker).to receive(:perform_async)
+ service.trigger(build)
+ end
+ end
+
+ describe "#cancel" do
+ before do
+ service.cancel(mr_merge_if_green_enabled)
+ end
+
+ it "resets all the merge_when_build_succeeds params" do
+ expect(mr_merge_if_green_enabled.merge_when_build_succeeds).to be_falsey
+ expect(mr_merge_if_green_enabled.merge_params).to eq({})
+ expect(mr_merge_if_green_enabled.merge_user).to be nil
+ end
+
+ it 'Posts a system note' do
+ note = mr_merge_if_green_enabled.notes.last
+ expect(note.note).to include 'Canceled the automatic merge'
+ end
+ end
+end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 7ee4488521d..450250ba032 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::RefreshService do
+describe MergeRequests::RefreshService, services: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:service) { MergeRequests::RefreshService }
@@ -17,7 +17,9 @@ describe MergeRequests::RefreshService do
source_project: @project,
source_branch: 'master',
target_branch: 'feature',
- target_project: @project)
+ target_project: @project,
+ merge_when_build_succeeds: true,
+ merge_user: @user)
@fork_merge_request = create(:merge_request,
source_project: @fork_project,
@@ -46,6 +48,7 @@ describe MergeRequests::RefreshService do
it { expect(@merge_request.notes).not_to be_empty }
it { expect(@merge_request).to be_open }
+ it { expect(@merge_request.merge_when_build_succeeds).to be_falsey}
it { expect(@fork_merge_request).to be_open }
it { expect(@fork_merge_request.notes).to be_empty }
end
@@ -146,6 +149,7 @@ describe MergeRequests::RefreshService do
end
end
+
def reload_mrs
@merge_request.reload
@fork_merge_request.reload
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index 9401bc3b558..ac0221998f5 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::ReopenService do
+describe MergeRequests::ReopenService, services: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user2) }
@@ -19,7 +19,9 @@ describe MergeRequests::ReopenService do
allow(service).to receive(:execute_hooks)
merge_request.state = :closed
- service.execute(merge_request)
+ perform_enqueued_jobs do
+ service.execute(merge_request)
+ end
end
it { expect(merge_request).to be_valid }
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 2ed51d223b7..2e9e6e0870d 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::UpdateService do
+describe MergeRequests::UpdateService, services: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
@@ -14,6 +14,17 @@ describe MergeRequests::UpdateService do
end
describe 'execute' do
+ def find_note(starting_with)
+ @merge_request.notes.find do |note|
+ note && note.note.start_with?(starting_with)
+ end
+ end
+
+ def update_merge_request(opts)
+ @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request.reload
+ end
+
context 'valid params' do
let(:opts) do
{
@@ -31,8 +42,10 @@ describe MergeRequests::UpdateService do
before do
allow(service).to receive(:execute_hooks)
- @merge_request = service.execute(merge_request)
- @merge_request.reload
+ perform_enqueued_jobs do
+ @merge_request = service.execute(merge_request)
+ @merge_request.reload
+ end
end
it { expect(@merge_request).to be_valid }
@@ -56,12 +69,6 @@ describe MergeRequests::UpdateService do
expect(email.subject).to include(merge_request.title)
end
- def find_note(starting_with)
- @merge_request.notes.find do |note|
- note && note.note.start_with?(starting_with)
- end
- end
-
it 'should create system note about merge_request reassign' do
note = find_note('Reassigned to')
@@ -90,5 +97,39 @@ describe MergeRequests::UpdateService do
expect(note.note).to eq 'Target branch changed from `master` to `target`'
end
end
+
+ context 'when MergeRequest has tasks' do
+ before { update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" }) }
+
+ 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" }) }
+
+ it 'creates system note about task status change' do
+ note1 = find_note('Marked the task **Task 1** as completed')
+ note2 = find_note('Marked the task **Task 2** as completed')
+
+ expect(note1).not_to be_nil
+ expect(note2).not_to be_nil
+ end
+ end
+
+ context 'when tasks are marked as incomplete' do
+ before do
+ update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" })
+ update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" })
+ end
+
+ it 'creates system note about task status change' do
+ note1 = find_note('Marked the task **Task 1** as incomplete')
+ note2 = find_note('Marked the task **Task 2** as incomplete')
+
+ expect(note1).not_to be_nil
+ expect(note2).not_to be_nil
+ end
+ end
+ end
+
end
end
diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb
index 034c0f22e12..1cd6eb2ab38 100644
--- a/spec/services/milestones/close_service_spec.rb
+++ b/spec/services/milestones/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Milestones::CloseService do
+describe Milestones::CloseService, services: true do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) }
diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb
index 757c9a226d8..c793026e300 100644
--- a/spec/services/milestones/create_service_spec.rb
+++ b/spec/services/milestones/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Milestones::CreateService do
+describe Milestones::CreateService, services: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index cc38d257792..a797a2fe4aa 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::CreateService do
+describe Notes::CreateService, services: true do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 520140917aa..d7a898e85ff 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1,8 +1,14 @@
require 'spec_helper'
-describe NotificationService do
+describe NotificationService, services: true do
let(:notification) { NotificationService.new }
+ around(:each) do |example|
+ perform_enqueued_jobs do
+ example.run
+ end
+ end
+
describe 'Keys' do
describe :new_key do
let!(:key) { create(:personal_key) }
@@ -10,8 +16,7 @@ describe NotificationService do
it { expect(notification.new_key(key)).to be_truthy }
it 'should sent email to key owner' do
- expect(Notify).to receive(:new_ssh_key_email).with(key.id)
- notification.new_key(key)
+ expect{ notification.new_key(key) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
end
end
end
@@ -23,8 +28,7 @@ describe NotificationService do
it { expect(notification.new_email(email)).to be_truthy }
it 'should send email to email owner' do
- expect(Notify).to receive(:new_email_email).with(email.id)
- notification.new_email(email)
+ expect{ notification.new_email(email) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
end
end
end
@@ -41,24 +45,28 @@ describe NotificationService do
project.team << [issue.author, :master]
project.team << [issue.assignee, :master]
project.team << [note.author, :master]
+ create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@subscribed_participant cc this guy')
end
describe :new_note do
it do
add_users_with_subscription(note.project, issue)
- should_email(@u_watcher.id)
- should_email(note.noteable.author_id)
- should_email(note.noteable.assignee_id)
- should_email(@u_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(note.author_id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_outsider_mentioned)
+ ActionMailer::Base.deliveries.clear
notification.new_note(note)
+
+ should_email(@u_watcher)
+ should_email(note.noteable.author)
+ should_email(note.noteable.assignee)
+ should_email(@u_mentioned)
+ should_email(@subscriber)
+ should_email(@subscribed_participant)
+ should_not_email(note.author)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_outsider_mentioned)
end
it 'filters out "mentioned in" notes' do
@@ -82,26 +90,20 @@ describe NotificationService do
group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id)
group_member.notification_level = Notification::N_GLOBAL
group_member.save
+ ActionMailer::Base.deliveries.clear
end
it do
- should_email(note.noteable.author_id)
- should_email(note.noteable.assignee_id)
- should_email(@u_mentioned.id)
- should_not_email(@u_watcher.id)
- should_not_email(note.author_id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.new_note(note)
- end
- end
- def should_email(user_id)
- expect(Notify).to receive(:note_issue_email).with(user_id, note.id)
- end
-
- def should_not_email(user_id)
- expect(Notify).not_to receive(:note_issue_email).with(user_id, note.id)
+ should_email(note.noteable.author)
+ should_email(note.noteable.assignee)
+ should_email(@u_mentioned)
+ should_not_email(@u_watcher)
+ should_not_email(note.author)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ end
end
end
@@ -113,24 +115,26 @@ describe NotificationService do
before do
build_team(note.project)
+ ActionMailer::Base.deliveries.clear
end
describe :new_note do
it do
+ notification.new_note(note)
+
# Notify all team members
note.project.team.members.each do |member|
# User with disabled notification should not be notified
next if member.id == @u_disabled.id
- should_email(member.id)
+ should_email(member)
end
- should_email(note.noteable.author_id)
- should_email(note.noteable.assignee_id)
- should_not_email(note.author_id)
- should_not_email(@u_mentioned.id)
- should_not_email(@u_disabled.id)
- should_not_email(@u_not_mentioned.id)
- notification.new_note(note)
+ should_email(note.noteable.author)
+ should_email(note.noteable.assignee)
+ should_not_email(note.author)
+ should_email(@u_mentioned)
+ should_not_email(@u_disabled)
+ should_email(@u_not_mentioned)
end
it 'filters out "mentioned in" notes' do
@@ -140,14 +144,6 @@ describe NotificationService do
notification.new_note(mentioned_note)
end
end
-
- def should_email(user_id)
- expect(Notify).to receive(:note_issue_email).with(user_id, note.id)
- end
-
- def should_not_email(user_id)
- expect(Notify).not_to receive(:note_issue_email).with(user_id, note.id)
- end
end
context 'commit note' do
@@ -156,43 +152,38 @@ describe NotificationService do
before do
build_team(note.project)
+ ActionMailer::Base.deliveries.clear
allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer)
end
- describe :new_note do
+ describe :new_note, :perform_enqueued_jobs do
it do
- should_email(@u_committer.id, note)
- should_email(@u_watcher.id, note)
- should_not_email(@u_mentioned.id, note)
- should_not_email(note.author_id, note)
- should_not_email(@u_participating.id, note)
- should_not_email(@u_disabled.id, note)
notification.new_note(note)
+
+ should_email(@u_committer)
+ should_email(@u_watcher)
+ should_not_email(@u_mentioned)
+ should_not_email(note.author)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
it do
note.update_attribute(:note, '@mention referenced')
- should_email(@u_committer.id, note)
- should_email(@u_watcher.id, note)
- should_email(@u_mentioned.id, note)
- should_not_email(note.author_id, note)
- should_not_email(@u_participating.id, note)
- should_not_email(@u_disabled.id, note)
notification.new_note(note)
+
+ should_email(@u_committer)
+ should_email(@u_watcher)
+ should_email(@u_mentioned)
+ should_not_email(note.author)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
it do
@u_committer.update_attributes(notification_level: Notification::N_MENTION)
- should_not_email(@u_committer.id, note)
notification.new_note(note)
- end
-
- def should_email(user_id, n)
- expect(Notify).to receive(:note_commit_email).with(user_id, n.id)
- end
-
- def should_not_email(user_id, n)
- expect(Notify).not_to receive(:note_commit_email).with(user_id, n.id)
+ should_not_email(@u_committer)
end
end
end
@@ -205,99 +196,69 @@ describe NotificationService do
before do
build_team(issue.project)
add_users_with_subscription(issue.project, issue)
+ ActionMailer::Base.deliveries.clear
end
describe :new_issue do
it do
- should_email(issue.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_not_email(@u_mentioned.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.new_issue(issue, @u_disabled)
+
+ should_email(issue.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_not_email(@u_mentioned)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
it do
issue.assignee.update_attributes(notification_level: Notification::N_MENTION)
- should_not_email(issue.assignee_id)
notification.new_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:new_issue_email).with(user_id, issue.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:new_issue_email).with(user_id, issue.id)
+ should_not_email(issue.assignee)
end
end
describe :reassigned_issue do
it 'should email new assignee' do
- should_email(issue.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
-
notification.reassigned_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:reassigned_issue_email).with(user_id, issue.id, nil, @u_disabled.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id, @u_disabled.id)
+ should_email(issue.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
describe :close_issue do
it 'should sent email to issue assignee and issue author' do
- should_email(issue.assignee_id)
- should_email(issue.author_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
-
notification.close_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
+ should_email(issue.assignee)
+ should_email(issue.author)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
describe :reopen_issue do
it 'should send email to issue assignee and issue author' do
- should_email(issue.assignee_id)
- should_email(issue.author_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
-
notification.reopen_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:issue_status_changed_email).with(user_id, issue.id, 'reopened', @u_disabled.id)
+ should_email(issue.assignee)
+ should_email(issue.author)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
end
end
end
@@ -309,108 +270,74 @@ describe NotificationService do
before do
build_team(merge_request.target_project)
add_users_with_subscription(merge_request.target_project, merge_request)
+ ActionMailer::Base.deliveries.clear
end
describe :new_merge_request do
it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.new_merge_request(merge_request, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:new_merge_request_email).with(user_id, merge_request.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:new_merge_request_email).with(user_id, merge_request.id)
+ should_email(merge_request.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
describe :reassigned_merge_request do
it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.reassigned_merge_request(merge_request, merge_request.author)
- end
- def should_email(user_id)
- expect(Notify).to receive(:reassigned_merge_request_email).with(user_id, merge_request.id, nil, merge_request.author_id)
- end
-
- def should_not_email(user_id)
- expect(Notify).not_to receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id, merge_request.author_id)
+ should_email(merge_request.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
describe :closed_merge_request do
it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.close_mr(merge_request, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
+ should_email(merge_request.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
describe :merged_merge_request do
it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.merge_mr(merge_request, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
+ should_email(merge_request.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
describe :reopen_merge_request do
it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_email(@u_participant_mentioned.id)
- should_email(@subscriber.id)
- should_not_email(@unsubscriber.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.reopen_mr(merge_request, @u_disabled)
- end
-
- def should_email(user_id)
- expect(Notify).to receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
- end
- def should_not_email(user_id)
- expect(Notify).not_to receive(:merge_request_status_email).with(user_id, merge_request.id, 'reopened', @u_disabled.id)
+ should_email(merge_request.assignee)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
end
@@ -420,22 +347,16 @@ describe NotificationService do
before do
build_team(project)
+ ActionMailer::Base.deliveries.clear
end
describe :project_was_moved do
it do
- should_email(@u_watcher.id)
- should_email(@u_participating.id)
- should_not_email(@u_disabled.id)
notification.project_was_moved(project, "gitlab/gitlab")
- end
- def should_email(user_id)
- expect(Notify).to receive(:project_was_moved_email).with(project.id, user_id, "gitlab/gitlab")
- end
-
- def should_not_email(user_id)
- expect(Notify).not_to receive(:project_was_moved_email).with(project.id, user_id, "gitlab/gitlab")
+ should_email(@u_watcher)
+ should_email(@u_participating)
+ should_not_email(@u_disabled)
end
end
end
@@ -462,11 +383,26 @@ describe NotificationService do
def add_users_with_subscription(project, issuable)
@subscriber = create :user
@unsubscriber = create :user
+ @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: Notification::N_PARTICIPATING)
+ project.team << [@subscribed_participant, :master]
project.team << [@subscriber, :master]
project.team << [@unsubscriber, :master]
issuable.subscriptions.create(user: @subscriber, subscribed: true)
+ issuable.subscriptions.create(user: @subscribed_participant, subscribed: true)
issuable.subscriptions.create(user: @unsubscriber, subscribed: false)
end
+
+ def sent_to_user?(user)
+ ActionMailer::Base.deliveries.map(&:to).flatten.count(user.email) == 1
+ end
+
+ def should_email(user)
+ expect(sent_to_user?(user)).to be_truthy
+ end
+
+ def should_not_email(user)
+ expect(sent_to_user?(user)).to be_falsey
+ end
end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index e81c4edb7d8..5d0b18558b1 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::CreateService do
+describe Projects::CreateService, services: true do
describe :create_by_user do
before do
@user = create :user
@@ -49,6 +49,13 @@ describe Projects::CreateService do
it { expect(@project.namespace).to eq(@group) }
end
+ context 'error handling' do
+ it 'handles invalid options' do
+ @opts.merge!({ default_branch: 'master' } )
+ expect(create_project(@user, @opts)).to eq(nil)
+ end
+ end
+
context 'wiki_enabled creates repository directory' do
context 'wiki_enabled true creates wiki repository directory' do
before do
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index e83eef0b1a2..1ec27077717 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::DestroyService do
+describe Projects::DestroyService, services: true do
let!(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace) }
let!(:path) { project.repository.path_to_repo }
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index ddee2e62dfc..5ceed5af9a5 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::DownloadService do
+describe Projects::DownloadService, services: true do
describe 'File service' do
before do
@user = create :user
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 1feba6ce048..d1ee60a0aea 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::ForkService do
+describe Projects::ForkService, services: true do
describe :fork_by_user do
before do
@from_namespace = create(:namespace)
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 47755bfc990..c46259431aa 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::TransferService do
+describe Projects::TransferService, services: true do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, namespace: user.namespace) }
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index b347fa15f87..c36d4581989 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::UpdateService do
+describe Projects::UpdateService, services: true do
describe :update_by_user do
before do
@user = create :user
diff --git a/spec/services/projects/upload_service_spec.rb b/spec/services/projects/upload_service_spec.rb
index 1b1a80d1fe7..9268a9fb1a2 100644
--- a/spec/services/projects/upload_service_spec.rb
+++ b/spec/services/projects/upload_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::UploadService do
+describe Projects::UploadService, services: true do
describe 'File service' do
before do
@user = create :user
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index f57bfaea879..7b3a9a75d7c 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Search::GlobalService' do
+describe 'Search::GlobalService', services: true do
let(:user) { create(:user) }
let(:public_user) { create(:user) }
let(:internal_user) { create(:user) }
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index a31fc1e4b07..febc78d2784 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SystemHooksService do
+describe SystemHooksService, services: true do
let(:user) { create :user }
let(:project) { create :project }
let(:project_member) { create :project_member }
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index a45130bd473..0a4f9b230e8 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SystemNoteService do
+describe SystemNoteService, services: true do
let(:project) { create(:project) }
let(:author) { create(:user) }
let(:noteable) { create(:issue, project: project) }
@@ -207,6 +207,32 @@ describe SystemNoteService do
end
end
+ describe '.merge_when_build_succeeds' do
+ let(:ci_commit) { build :ci_commit_without_jobs }
+ let(:noteable) { create :merge_request }
+
+ subject { described_class.merge_when_build_succeeds(noteable, project, author, noteable.last_commit) }
+
+ it_behaves_like 'a system note'
+
+ it "posts the Merge When Build Succeeds system note" do
+ expect(subject.note).to match /Enabled an automatic merge when the build for (\w+\/\w+@)?[0-9a-f]{40} succeeds/
+ end
+ end
+
+ describe '.cancel_merge_when_build_succeeds' do
+ let(:ci_commit) { build :ci_commit_without_jobs }
+ let(:noteable) { create :merge_request }
+
+ subject { described_class.cancel_merge_when_build_succeeds(noteable, project, author) }
+
+ it_behaves_like 'a system note'
+
+ it "posts the Merge When Build Succeeds system note" do
+ expect(subject.note).to eq "Canceled the automatic merge"
+ end
+ end
+
describe '.change_title' do
subject { described_class.change_title(noteable, project, author, 'Old title') }
diff --git a/spec/services/test_hook_service_spec.rb b/spec/services/test_hook_service_spec.rb
index 226196eedae..f034f251ba4 100644
--- a/spec/services/test_hook_service_spec.rb
+++ b/spec/services/test_hook_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe TestHookService do
+describe TestHookService, services: true do
let(:user) { create :user }
let(:project) { create :project }
let(:hook) { create :project_hook, project: project }
diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb
new file mode 100644
index 00000000000..bba211089a8
--- /dev/null
+++ b/spec/services/update_release_service_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe UpdateReleaseService, services: true do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:tag_name) { project.repository.tag_names.first }
+ let(:description) { 'Awesome release!' }
+ let(:new_description) { 'The best release!' }
+ let(:service) { UpdateReleaseService.new(project, user) }
+
+ context 'with an existing release' do
+ let(:create_service) { CreateReleaseService.new(project, user) }
+
+ before do
+ create_service.execute(tag_name, description)
+ end
+
+ it 'successfully updates an existing release' do
+ result = service.execute(tag_name, new_description)
+ expect(result[:status]).to eq(:success)
+ expect(project.releases.find_by(tag: tag_name).description).to eq(new_description)
+ end
+ end
+
+ it 'raises an error if the tag does not exist' do
+ result = service.execute("foobar", description)
+ expect(result[:status]).to eq(:error)
+ end
+
+ it 'raises an error if the release does not exist' do
+ result = service.execute(tag_name, description)
+ expect(result[:status]).to eq(:error)
+ end
+end
diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb
index d7c516e3934..48d114896d0 100644
--- a/spec/services/update_snippet_service_spec.rb
+++ b/spec/services/update_snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UpdateSnippetService do
+describe UpdateSnippetService, services: true do
before do
@user = create :user
@admin = create :user, admin: true
@@ -42,7 +42,7 @@ describe UpdateSnippetService do
CreateSnippetService.new(project, user, opts).execute
end
- def update_snippet(project = nil, user, snippet, opts)
+ def update_snippet(project, user, snippet, opts)
UpdateSnippetService.new(project, user, snippet, opts).execute
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 2be13bb3e6a..0225a0ee53f 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -31,6 +31,7 @@ RSpec.configure do |config|
config.include StubConfiguration
config.include RelativeUrl, type: feature
config.include TestEnv
+ config.include ActiveJob::TestHelper
config.include StubGitlabCalls
config.include StubGitlabData
config.include BenchmarkMatchers, benchmark: true
diff --git a/spec/support/filter_spec_helper.rb b/spec/support/filter_spec_helper.rb
index 97e5c270a59..d6e03cbef3d 100644
--- a/spec/support/filter_spec_helper.rb
+++ b/spec/support/filter_spec_helper.rb
@@ -1,4 +1,4 @@
-# Helper methods for Gitlab::Markdown filter specs
+# Helper methods for Banzai filter specs
#
# Must be included into specs manually
module FilterSpecHelper
@@ -10,36 +10,49 @@ module FilterSpecHelper
# if none is provided.
#
# html - HTML String to pass to the filter's `call` method.
- # contexts - Hash context for the filter. (default: {project: project})
+ # context - Hash context for the filter. (default: {project: project})
#
# Returns a Nokogiri::XML::DocumentFragment
- def filter(html, contexts = {})
+ def filter(html, context = {})
if defined?(project)
- contexts.reverse_merge!(project: project)
+ context.reverse_merge!(project: project)
end
- described_class.call(html, contexts)
+ described_class.call(html, context)
end
# Run text through HTML::Pipeline with the current filter and return the
# result Hash
#
# body - String text to run through the pipeline
- # contexts - Hash context for the filter. (default: {project: project})
+ # context - Hash context for the filter. (default: {project: project})
#
# Returns the Hash
- def pipeline_result(body, contexts = {})
- contexts.reverse_merge!(project: project) if defined?(project)
+ def pipeline_result(body, context = {})
+ context.reverse_merge!(project: project) if defined?(project)
- pipeline = HTML::Pipeline.new([described_class], contexts)
+ pipeline = HTML::Pipeline.new([described_class], context)
pipeline.call(body)
end
- def reference_pipeline_result(body, contexts = {})
- contexts.reverse_merge!(project: project) if defined?(project)
+ def reference_pipeline(context = {})
+ context.reverse_merge!(project: project) if defined?(project)
- pipeline = HTML::Pipeline.new([described_class, Gitlab::Markdown::ReferenceGathererFilter], contexts)
- pipeline.call(body)
+ filters = [
+ Banzai::Filter::AutolinkFilter,
+ described_class,
+ Banzai::Filter::ReferenceGathererFilter
+ ]
+
+ HTML::Pipeline.new(filters, context)
+ end
+
+ def reference_pipeline_result(body, context = {})
+ reference_pipeline(context).call(body)
+ end
+
+ def reference_filter(html, context = {})
+ reference_pipeline(context).to_document(html)
end
# Modify a String reference to make it invalid
diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb
index bedc1a7f1db..d6d3062a197 100644
--- a/spec/support/markdown_feature.rb
+++ b/spec/support/markdown_feature.rb
@@ -93,6 +93,10 @@ class MarkdownFeature
end
end
+ def urls
+ Gitlab::Application.routes.url_helpers
+ end
+
def raw_markdown
markdown = File.read(Rails.root.join('spec/fixtures/markdown.md.erb'))
ERB.new(markdown).result(binding)
diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb
index 7500d0fdf80..7eadcd58c1f 100644
--- a/spec/support/matchers/markdown_matchers.rb
+++ b/spec/support/matchers/markdown_matchers.rb
@@ -71,7 +71,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-project_member', count: 3)
+ expect(actual).to have_selector('a.gfm.gfm-project_member', count: 4)
end
end
@@ -80,7 +80,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-issue', count: 3)
+ expect(actual).to have_selector('a.gfm.gfm-issue', count: 6)
end
end
@@ -89,7 +89,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-merge_request', count: 3)
+ expect(actual).to have_selector('a.gfm.gfm-merge_request', count: 6)
expect(actual).to have_selector('em a.gfm-merge_request')
end
end
@@ -99,7 +99,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-snippet', count: 2)
+ expect(actual).to have_selector('a.gfm.gfm-snippet', count: 5)
end
end
@@ -108,7 +108,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-commit_range', count: 2)
+ expect(actual).to have_selector('a.gfm.gfm-commit_range', count: 5)
end
end
@@ -117,7 +117,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-commit', count: 2)
+ expect(actual).to have_selector('a.gfm.gfm-commit', count: 5)
end
end
@@ -126,7 +126,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-label', count: 3)
+ expect(actual).to have_selector('a.gfm.gfm-label', count: 4)
end
end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index 3bb568f4d49..fce91015fd4 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -4,18 +4,18 @@
# - let(:backref_text) { "the way that +subject+ should refer to itself in backreferences " }
# - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
-def common_mentionable_setup
+shared_context 'mentionable context' do
let(:project) { subject.project }
let(:author) { subject.author }
let(:mentioned_issue) { create(:issue, project: project) }
let!(:mentioned_mr) { create(:merge_request, :simple, source_project: project) }
- let(:mentioned_commit) { project.commit }
+ let(:mentioned_commit) { project.commit("HEAD~1") }
let(:ext_proj) { create(:project, :public) }
let(:ext_issue) { create(:issue, project: ext_proj) }
let(:ext_mr) { create(:merge_request, :simple, source_project: ext_proj) }
- let(:ext_commit) { ext_proj.commit }
+ let(:ext_commit) { ext_proj.commit("HEAD~2") }
# Override to add known commits to the repository stub.
let(:extra_commits) { [] }
@@ -45,21 +45,18 @@ def common_mentionable_setup
before do
# Wire the project's repository to return the mentioned commit, and +nil+
# for any unrecognized commits.
- commitmap = {
- mentioned_commit.id => mentioned_commit
- }
- extra_commits.each { |c| commitmap[c.short_id] = c }
-
- allow(Project).to receive(:find).and_call_original
- allow(Project).to receive(:find).with(project.id.to_s).and_return(project)
- allow(project.repository).to receive(:commit) { |sha| commitmap[sha] }
+ allow_any_instance_of(::Repository).to receive(:commit).and_call_original
+ allow_any_instance_of(::Repository).to receive(:commit).with(mentioned_commit.short_id).and_return(mentioned_commit)
+ extra_commits.each do |commit|
+ allow_any_instance_of(::Repository).to receive(:commit).with(commit.short_id).and_return(commit)
+ end
set_mentionable_text.call(ref_string)
end
end
shared_examples 'a mentionable' do
- common_mentionable_setup
+ include_context 'mentionable context'
it 'generates a descriptive back-reference' do
expect(subject.gfm_reference).to eq(backref_text)
@@ -91,7 +88,7 @@ shared_examples 'a mentionable' do
end
shared_examples 'an editable mentionable' do
- common_mentionable_setup
+ include_context 'mentionable context'
it_behaves_like 'a mentionable'
diff --git a/spec/support/repo_helpers.rb b/spec/support/repo_helpers.rb
index aadf791bf3f..aa8258d6dad 100644
--- a/spec/support/repo_helpers.rb
+++ b/spec/support/repo_helpers.rb
@@ -45,12 +45,12 @@ eos
def another_sample_commit
OpenStruct.new(
- id: "e56497bb5f03a90a51293fc6d516788730953899",
- parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
- author_full_name: "Sytse Sijbrandij",
- author_email: "sytse@gitlab.com",
- files_changed_count: 1,
- message: <<eos
+ id: "e56497bb5f03a90a51293fc6d516788730953899",
+ parent_id: '4cd80ccab63c82b4bad16faa5193fbd2aa06df40',
+ author_full_name: "Sytse Sijbrandij",
+ author_email: "sytse@gitlab.com",
+ files_changed_count: 1,
+ message: <<eos
Add directory structure for tree_helper spec
This directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module
diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb
index 5b3eb1bfc5f..eec2e681117 100644
--- a/spec/support/stub_gitlab_calls.rb
+++ b/spec/support/stub_gitlab_calls.rb
@@ -21,6 +21,10 @@ module StubGitlabCalls
allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { ci_yaml }
end
+ def stub_ci_builds_disabled
+ allow_any_instance_of(Project).to receive(:builds_enabled?).and_return(false)
+ end
+
private
def gitlab_url
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 787670e9297..4f4743bff6d 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -12,6 +12,7 @@ module TestEnv
'fix' => '48f0be4',
'improve/awesome' => '5937ac0',
'markdown' => '0ed8c6c',
+ 'lfs' => 'be93687',
'master' => '5937ac0',
"'test'" => 'e56497b',
}
@@ -21,7 +22,8 @@ module TestEnv
# We currently only need a subset of the branches
FORKED_BRANCH_SHA = {
'add-submodule-version-bump' => '3f547c08',
- 'master' => '5937ac0'
+ 'master' => '5937ac0',
+ 'remove-submodule' => '2a33e0c0'
}
# Test environment
diff --git a/spec/support/wait_for_ajax.rb b/spec/support/wait_for_ajax.rb
new file mode 100644
index 00000000000..692d219e9f1
--- /dev/null
+++ b/spec/support/wait_for_ajax.rb
@@ -0,0 +1,11 @@
+module WaitForAjax
+ def wait_for_ajax
+ Timeout.timeout(Capybara.default_wait_time) do
+ loop until finished_all_ajax_requests?
+ end
+ end
+
+ def finished_all_ajax_requests?
+ page.evaluate_script('jQuery.active').zero?
+ end
+end
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index fb5e74af648..63bed2414df 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -16,7 +16,7 @@ describe 'gitlab:app namespace rake task' do
end
def reenable_backup_sub_tasks
- %w{db repo uploads builds artifacts}.each do |subtask|
+ %w{db repo uploads builds artifacts lfs}.each do |subtask|
Rake::Task["gitlab:backup:#{subtask}:create"].reenable
end
end
@@ -49,7 +49,7 @@ describe 'gitlab:app namespace rake task' do
to raise_error(SystemExit)
end
- it 'should invoke restoration on mach' do
+ it 'should invoke restoration on match' do
allow(YAML).to receive(:load_file).
and_return({ gitlab_version: gitlab_version })
expect(Rake::Task["gitlab:backup:db:restore"]).to receive(:invoke)
@@ -57,6 +57,7 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task["gitlab:backup:builds:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:uploads:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:artifacts:restore"]).to receive(:invoke)
+ expect(Rake::Task["gitlab:backup:lfs:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:shell:setup"]).to receive(:invoke)
expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end
@@ -114,7 +115,7 @@ describe 'gitlab:app namespace rake task' do
it 'should set correct permissions on the tar contents' do
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz}
+ %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz}
)
expect(exit_status).to eq(0)
expect(tar_contents).to match('db/')
@@ -122,12 +123,13 @@ describe 'gitlab:app namespace rake task' do
expect(tar_contents).to match('repositories/')
expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).to match('artifacts.tar.gz')
+ expect(tar_contents).to match('lfs.tar.gz')
expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz)\/$/)
end
it 'should delete temp directories' do
temp_dirs = Dir.glob(
- File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts}')
+ File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs}')
)
expect(temp_dirs).to be_empty
@@ -163,13 +165,14 @@ describe 'gitlab:app namespace rake task' do
it "does not contain skipped item" do
tar_contents, _exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz}
+ %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz}
)
expect(tar_contents).to match('db/')
expect(tar_contents).to match('uploads.tar.gz')
expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).to match('artifacts.tar.gz')
+ expect(tar_contents).to match('lfs.tar.gz')
expect(tar_contents).not_to match('repositories/')
end
@@ -183,6 +186,7 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task["gitlab:backup:uploads:restore"]).not_to receive :invoke
expect(Rake::Task["gitlab:backup:builds:restore"]).to receive :invoke
expect(Rake::Task["gitlab:backup:artifacts:restore"]).to receive :invoke
+ expect(Rake::Task["gitlab:backup:lfs:restore"]).to receive :invoke
expect(Rake::Task["gitlab:shell:setup"]).to receive :invoke
expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end
diff --git a/spec/workers/build_email_worker_spec.rb b/spec/workers/build_email_worker_spec.rb
new file mode 100644
index 00000000000..98deae0a588
--- /dev/null
+++ b/spec/workers/build_email_worker_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe BuildEmailWorker do
+ include RepoHelpers
+
+ let(:build) { create(:ci_build) }
+ let(:user) { create(:user) }
+ let(:data) { Gitlab::BuildDataBuilder.build(build) }
+
+ subject { BuildEmailWorker.new }
+
+ before do
+ allow(build).to receive(:execute_hooks).and_return(false)
+ build.success
+ end
+
+ describe "#perform" do
+ it "sends mail" do
+ subject.perform(build.id, [user.email], data.stringify_keys)
+
+ email = ActionMailer::Base.deliveries.last
+ expect(email.subject).to include('Build success for')
+ expect(email.to).to eq([user.email])
+ end
+
+ it "gracefully handles an input SMTP error" do
+ ActionMailer::Base.deliveries.clear
+ allow(Notify).to receive(:build_success_email).and_raise(Net::SMTPFatalError)
+
+ subject.perform(build.id, [user.email], data.stringify_keys)
+
+ expect(ActionMailer::Base.deliveries.count).to eq(0)
+ end
+ end
+end
diff --git a/spec/workers/email_receiver_worker_spec.rb b/spec/workers/email_receiver_worker_spec.rb
index 65a8d7d9197..de40a6f78af 100644
--- a/spec/workers/email_receiver_worker_spec.rb
+++ b/spec/workers/email_receiver_worker_spec.rb
@@ -21,12 +21,14 @@ describe EmailReceiverWorker do
end
it "sends out a rejection email" do
- described_class.new.perform(raw_message)
-
- email = ActionMailer::Base.deliveries.last
- expect(email).not_to be_nil
- expect(email.to).to eq(["jake@adventuretime.ooo"])
- expect(email.subject).to include("Rejected")
+ perform_enqueued_jobs do
+ described_class.new.perform(raw_message)
+
+ email = ActionMailer::Base.deliveries.last
+ expect(email).not_to be_nil
+ expect(email.to).to eq(["jake@adventuretime.ooo"])
+ expect(email.subject).to include("Rejected")
+ end
end
end
end
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 245f066df1f..dae31992620 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -9,20 +9,22 @@ describe RepositoryForkWorker do
describe "#perform" do
it "creates a new repository from a fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).with(
- project.path_with_namespace,
- fork_project.namespace.path).
- and_return(true)
+ project.path_with_namespace,
+ fork_project.namespace.path
+ ).and_return(true)
- subject.perform(project.id,
- project.path_with_namespace,
- fork_project.namespace.path)
+ subject.perform(
+ project.id,
+ project.path_with_namespace,
+ fork_project.namespace.path)
end
it "handles bad fork" do
expect_any_instance_of(Gitlab::Shell).to receive(:fork_repository).and_return(false)
- subject.perform(project.id,
- project.path_with_namespace,
- fork_project.namespace.path)
+ subject.perform(
+ project.id,
+ project.path_with_namespace,
+ fork_project.namespace.path)
end
end
end
diff --git a/spec/workers/stuck_ci_builds_worker_spec.rb b/spec/workers/stuck_ci_builds_worker_spec.rb
index f9d87d97014..665ec20f224 100644
--- a/spec/workers/stuck_ci_builds_worker_spec.rb
+++ b/spec/workers/stuck_ci_builds_worker_spec.rb
@@ -15,7 +15,7 @@ describe StuckCiBuildsWorker do
end
it 'gets dropped if it was updated over 2 days ago' do
- build.update!(updated_at: 2.day.ago)
+ build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform
is_expected.to eq('failed')
end
@@ -35,7 +35,7 @@ describe StuckCiBuildsWorker do
end
it "is still #{status}" do
- build.update!(updated_at: 2.day.ago)
+ build.update!(updated_at: 2.days.ago)
StuckCiBuildsWorker.new.perform
is_expected.to eq(status)
end