summaryrefslogtreecommitdiff
path: root/spec/lib
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib')
-rw-r--r--spec/lib/additional_email_headers_interceptor_spec.rb12
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb2
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb14
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/emoji_filter_spec.rb112
-rw-r--r--spec/lib/banzai/filter/gollum_tags_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/image_link_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb37
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb15
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/plantuml_filter_spec.rb32
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/sanitization_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb8
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb51
-rw-r--r--spec/lib/banzai/filter/video_link_filter_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb6
-rw-r--r--spec/lib/bitbucket/collection_spec.rb2
-rw-r--r--spec/lib/bitbucket/representation/repo_spec.rb4
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb119
-rw-r--r--spec/lib/constraints/project_url_constrainer_spec.rb6
-rw-r--r--spec/lib/event_filter_spec.rb22
-rw-r--r--spec/lib/expand_variables_spec.rb31
-rw-r--r--spec/lib/extracts_path_spec.rb6
-rw-r--r--spec/lib/git_ref_validator_spec.rb5
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb23
-rw-r--r--spec/lib/gitlab/auth/unique_ips_limiter_spec.rb57
-rw-r--r--spec/lib/gitlab/auth_spec.rb156
-rw-r--r--spec/lib/gitlab/award_emoji_spec.rb41
-rw-r--r--spec/lib/gitlab/badge/build/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/build/status_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/coverage/metadata_spec.rb2
-rw-r--r--spec/lib/gitlab/badge/shared/metadata.rb10
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb10
-rw-r--r--spec/lib/gitlab/blame_spec.rb2
-rw-r--r--spec/lib/gitlab/chat_commands/command_spec.rb52
-rw-r--r--spec/lib/gitlab/chat_commands/deploy_spec.rb24
-rw-r--r--spec/lib/gitlab/chat_commands/issue_new_spec.rb (renamed from spec/lib/gitlab/chat_commands/issue_create_spec.rb)14
-rw-r--r--spec/lib/gitlab/chat_commands/issue_search_spec.rb12
-rw-r--r--spec/lib/gitlab/chat_commands/issue_show_spec.rb25
-rw-r--r--spec/lib/gitlab/chat_commands/presenters/access_spec.rb49
-rw-r--r--spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb47
-rw-r--r--spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb17
-rw-r--r--spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb23
-rw-r--r--spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb52
-rw-r--r--spec/lib/gitlab/checks/change_access_spec.rb14
-rw-r--r--spec/lib/gitlab/checks/force_push_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/image_spec.rb67
-rw-r--r--spec/lib/gitlab/ci/build/step_spec.rb39
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/entry/commands_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/coverage_spec.rb54
-rw-r--r--spec/lib/gitlab/ci/config/entry/environment_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/factory_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/config/entry/global_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb93
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/key_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/paths_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/script_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/variables_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb140
-rw-r--r--spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb110
-rw-r--r--spec/lib/gitlab/ci/status/build/play_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/status/build/retryable_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/build/stop_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/status/canceled_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/created_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/factory_spec.rb133
-rw-r--r--spec/lib/gitlab/ci/status/failed_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/manual_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/status/pending_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb42
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/factory_spec.rb70
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb69
-rw-r--r--spec/lib/gitlab/ci/status/running_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/skipped_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/success_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/success_warning_spec.rb75
-rw-r--r--spec/lib/gitlab/ci/trace_reader_spec.rb16
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb8
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb8
-rw-r--r--spec/lib/gitlab/conflict/parser_spec.rb89
-rw-r--r--spec/lib/gitlab/contributions_calendar_spec.rb2
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb68
-rw-r--r--spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb45
-rw-r--r--spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb10
-rw-r--r--spec/lib/gitlab/data_builder/build_spec.rb26
-rw-r--r--spec/lib/gitlab/data_builder/note_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/pipeline_spec.rb2
-rw-r--r--spec/lib/gitlab/data_builder/push_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb86
-rw-r--r--spec/lib/gitlab/database_spec.rb99
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb22
-rw-r--r--spec/lib/gitlab/diff/line_mapper_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/parallel_diff_spec.rb4
-rw-r--r--spec/lib/gitlab/diff/parser_spec.rb48
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/position_tracer_spec.rb14
-rw-r--r--spec/lib/gitlab/email/email_shared_blocks.rb2
-rw-r--r--spec/lib/gitlab/email/handler/create_issue_handler_spec.rb4
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb10
-rw-r--r--spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb61
-rw-r--r--spec/lib/gitlab/email/message/repository_push_spec.rb2
-rw-r--r--spec/lib/gitlab/etag_caching/middleware_spec.rb176
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/gfm/uploads_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/git/blob_snippet_spec.rb4
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb193
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb28
-rw-r--r--spec/lib/gitlab/git/compare_spec.rb10
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb6
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb37
-rw-r--r--spec/lib/gitlab/git/hook_spec.rb2
-rw-r--r--spec/lib/gitlab/git/index_spec.rb220
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb300
-rw-r--r--spec/lib/gitlab/git/rev_list_spec.rb2
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb11
-rw-r--r--spec/lib/gitlab/git/util_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_spec.rb50
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb4
-rw-r--r--spec/lib/gitlab/git_spec.rb23
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_spec.rb58
-rw-r--r--spec/lib/gitlab/gitaly_client/notifications_spec.rb13
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb26
-rw-r--r--spec/lib/gitlab/github_import/branch_formatter_spec.rb14
-rw-r--r--spec/lib/gitlab/github_import/comment_formatter_spec.rb20
-rw-r--r--spec/lib/gitlab/github_import/importer_spec.rb123
-rw-r--r--spec/lib/gitlab/github_import/issue_formatter_spec.rb29
-rw-r--r--spec/lib/gitlab/github_import/label_formatter_spec.rb4
-rw-r--r--spec/lib/gitlab/github_import/pull_request_formatter_spec.rb127
-rw-r--r--spec/lib/gitlab/github_import/release_formatter_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/user_formatter_spec.rb39
-rw-r--r--spec/lib/gitlab/google_code_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/graphs/commits_spec.rb2
-rw-r--r--spec/lib/gitlab/highlight_spec.rb12
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml11
-rw-r--r--spec/lib/gitlab/import_export/attribute_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/avatar_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/file_importer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/import_export_spec.rb5
-rw-r--r--spec/lib/gitlab/import_export/members_mapper_spec.rb48
-rw-r--r--spec/lib/gitlab/import_export/model_configuration_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project.json76
-rw-r--r--spec/lib/gitlab/import_export/project.light.json48
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb176
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb75
-rw-r--r--spec/lib/gitlab/import_export/reader_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/relation_factory_spec.rb15
-rw-r--r--spec/lib/gitlab/import_export/repo_bundler_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb40
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml15
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb4
-rw-r--r--spec/lib/gitlab/import_sources_spec.rb38
-rw-r--r--spec/lib/gitlab/incoming_email_spec.rb57
-rw-r--r--spec/lib/gitlab/job_waiter_spec.rb30
-rw-r--r--spec/lib/gitlab/kubernetes_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/access_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/auth_hash_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb6
-rw-r--r--spec/lib/gitlab/metrics/instrumentation_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/method_call_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/metric_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/system_spec.rb6
-rw-r--r--spec/lib/gitlab/metrics/transaction_spec.rb4
-rw-r--r--spec/lib/gitlab/middleware/go_spec.rb95
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb16
-rw-r--r--spec/lib/gitlab/optimistic_locking_spec.rb19
-rw-r--r--spec/lib/gitlab/other_markup.rb22
-rw-r--r--spec/lib/gitlab/polling_interval_spec.rb34
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb123
-rw-r--r--spec/lib/gitlab/project_transfer_spec.rb (renamed from spec/lib/gitlab/uploads_transfer_spec.rb)11
-rw-r--r--spec/lib/gitlab/prometheus_spec.rb143
-rw-r--r--spec/lib/gitlab/redis_spec.rb59
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb97
-rw-r--r--spec/lib/gitlab/regex_spec.rb81
-rw-r--r--spec/lib/gitlab/repo_path_spec.rb22
-rw-r--r--spec/lib/gitlab/request_context_spec.rb30
-rw-r--r--spec/lib/gitlab/route_map_spec.rb90
-rw-r--r--spec/lib/gitlab/saml/user_spec.rb21
-rw-r--r--spec/lib/gitlab/search_results_spec.rb2
-rw-r--r--spec/lib/gitlab/serializer/ci/variables_spec.rb (renamed from spec/lib/gitlab/serialize/ci/variables_spec.rb)5
-rw-r--r--spec/lib/gitlab/serializer/pagination_spec.rb49
-rw-r--r--spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb12
-rw-r--r--spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb14
-rw-r--r--spec/lib/gitlab/sidekiq_status_spec.rb76
-rw-r--r--spec/lib/gitlab/slash_commands/extractor_spec.rb8
-rw-r--r--spec/lib/gitlab/template/issue_template_spec.rb19
-rw-r--r--spec/lib/gitlab/template/merge_request_template_spec.rb19
-rw-r--r--spec/lib/gitlab/themes_spec.rb48
-rw-r--r--spec/lib/gitlab/upgrader_spec.rb3
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb31
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb2
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb30
-rw-r--r--spec/lib/gitlab/user_access_spec.rb9
-rw-r--r--spec/lib/gitlab/utils_spec.rb4
-rw-r--r--spec/lib/gitlab/view/presenter/delegated_spec.rb14
-rw-r--r--spec/lib/gitlab/view/presenter/factory_spec.rb7
-rw-r--r--spec/lib/gitlab/view/presenter/simple_spec.rb15
-rw-r--r--spec/lib/gitlab/visibility_level_spec.rb21
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb128
-rw-r--r--spec/lib/light_url_builder_spec.rb2
-rw-r--r--spec/lib/mattermost/command_spec.rb6
-rw-r--r--spec/lib/mattermost/team_spec.rb29
-rw-r--r--spec/lib/repository_cache_spec.rb2
209 files changed, 5009 insertions, 1525 deletions
diff --git a/spec/lib/additional_email_headers_interceptor_spec.rb b/spec/lib/additional_email_headers_interceptor_spec.rb
new file mode 100644
index 00000000000..580450eef1e
--- /dev/null
+++ b/spec/lib/additional_email_headers_interceptor_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe AdditionalEmailHeadersInterceptor do
+ it 'adds Auto-Submitted header' do
+ mail = ActionMailer::Base.mail(to: 'test@mail.com', from: 'info@mail.com', body: 'hello').deliver
+
+ expect(mail.header['To'].value).to eq('test@mail.com')
+ expect(mail.header['From'].value).to eq('info@mail.com')
+ expect(mail.header['Auto-Submitted'].value).to eq('auto-generated')
+ expect(mail.header['X-Auto-Response-Suppress'].value).to eq('All')
+ end
+end
diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
index 81b9a513ce3..deaabceef1c 100644
--- a/spec/lib/banzai/cross_project_reference_spec.rb
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -24,7 +24,7 @@ describe Banzai::CrossProjectReference, lib: true do
it 'returns the referenced project' do
project2 = double('referenced project')
- expect(Project).to receive(:find_with_namespace).
+ expect(Project).to receive(:find_by_full_path).
with('cross/reference').and_return(project2)
expect(project_from_ref('cross/reference')).to eq project2
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index 9703e2315b8..deadc36524c 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit1) { project.commit("HEAD~2") }
let(:commit2) { project.commit }
@@ -99,7 +99,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
end
context 'cross-project / cross-namespace complete reference' do
- let(:project2) { create(:project, :public) }
+ let(:project2) { create(:project, :public, :repository) }
let(:reference) { "#{project2.path_with_namespace}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
@@ -133,8 +133,8 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
context 'cross-project / same-namespace complete reference' do
let(:namespace) { create(:namespace) }
- let(:project) { create(:project, :public, namespace: namespace) }
- let(:project2) { create(:project, :public, path: "same-namespace", namespace: namespace) }
+ let(:project) { create(:project, :public, :repository, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, path: "same-namespace", namespace: namespace) }
let(:reference) { "#{project2.path}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
@@ -168,8 +168,8 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
context 'cross-project shorthand reference' do
let(:namespace) { create(:namespace) }
- let(:project) { create(:project, :public, namespace: namespace) }
- let(:project2) { create(:project, :public, path: "same-namespace", namespace: namespace) }
+ let(:project) { create(:project, :public, :repository, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, path: "same-namespace", namespace: namespace) }
let(:reference) { "#{project2.path}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
@@ -203,7 +203,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
context 'cross-project URL reference' do
let(:namespace) { create(:namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:range) { CommitRange.new("#{commit1.id}...master", project) }
let(:reference) { urls.namespace_project_compare_url(project2.namespace, project2, from: commit1.id, to: 'master') }
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index 2e6dcc3a434..a19aac61229 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::CommitReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
it 'requires project context' do
@@ -96,7 +96,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project / cross-namespace complete reference' do
let(:namespace) { create(:namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
@@ -122,7 +122,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project / same-namespace complete reference' do
let(:namespace) { create(:namespace) }
let(:project) { create(:empty_project, namespace: namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
@@ -148,7 +148,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project shorthand reference' do
let(:namespace) { create(:namespace) }
let(:project) { create(:empty_project, namespace: namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
@@ -173,7 +173,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
context 'cross-project URL reference' do
let(:namespace) { create(:namespace) }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { urls.namespace_project_commit_url(project2.namespace, project2, commit.id) }
diff --git a/spec/lib/banzai/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb
index c8e62f528df..707212e07fd 100644
--- a/spec/lib/banzai/filter/emoji_filter_spec.rb
+++ b/spec/lib/banzai/filter/emoji_filter_spec.rb
@@ -14,12 +14,12 @@ describe Banzai::Filter::EmojiFilter, lib: true do
it 'replaces supported name emoji' do
doc = filter('<p>:heart:</p>')
- expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/2764.png'
+ expect(doc.css('gl-emoji').first.text).to eq '❤'
end
it 'replaces supported unicode emoji' do
doc = filter('<p>❤️</p>')
- expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/2764.png'
+ expect(doc.css('gl-emoji').first.text).to eq '❤'
end
it 'ignores unsupported emoji' do
@@ -30,152 +30,78 @@ describe Banzai::Filter::EmojiFilter, lib: true do
it 'correctly encodes the URL' do
doc = filter('<p>:+1:</p>')
- expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/1F44D.png'
+ expect(doc.css('gl-emoji').first.text).to eq '👍'
end
it 'correctly encodes unicode to the URL' do
doc = filter('<p>👍</p>')
- expect(doc.css('img').first.attr('src')).to eq 'https://foo.com/assets/1F44D.png'
+ expect(doc.css('gl-emoji').first.text).to eq '👍'
end
it 'matches at the start of a string' do
doc = filter(':+1:')
- expect(doc.css('img').size).to eq 1
+ expect(doc.css('gl-emoji').size).to eq 1
end
it 'unicode matches at the start of a string' do
doc = filter("'👍'")
- expect(doc.css('img').size).to eq 1
+ expect(doc.css('gl-emoji').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
+ expect(doc.css('gl-emoji').size).to eq 1
end
it 'unicode matches at the end of a string' do
doc = filter('This gets a 👍')
- expect(doc.css('img').size).to eq 1
+ expect(doc.css('gl-emoji').size).to eq 1
end
it 'matches with adjacent text' do
doc = filter('+1 (:+1:)')
- expect(doc.css('img').size).to eq 1
+ expect(doc.css('gl-emoji').size).to eq 1
end
it 'unicode matches with adjacent text' do
doc = filter('+1 (👍)')
- expect(doc.css('img').size).to eq 1
+ expect(doc.css('gl-emoji').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
+ expect(doc.css('gl-emoji').size).to eq 3
end
it 'unicode matches multiple emoji in a row' do
doc = filter("'🙈🙉🙊'")
- expect(doc.css('img').size).to eq 3
+ expect(doc.css('gl-emoji').size).to eq 3
end
it 'mixed 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 6
+ expect(doc.css('gl-emoji').size).to eq 6
end
- it 'has a title attribute' do
+ it 'has a data-name attribute' do
doc = filter(':-1:')
- expect(doc.css('img').first.attr('title')).to eq ':-1:'
+ expect(doc.css('gl-emoji').first.attr('data-name')).to eq 'thumbsdown'
end
- it 'unicode has a title attribute' do
- doc = filter("'👎'")
- expect(doc.css('img').first.attr('title')).to eq ':thumbsdown:'
- end
-
- it 'has an alt attribute' do
+ it 'has a data-unicode-version attribute' do
doc = filter(':-1:')
- expect(doc.css('img').first.attr('alt')).to eq ':-1:'
- end
-
- it 'unicode has an alt attribute' do
- doc = filter("'👎'")
- expect(doc.css('img').first.attr('alt')).to eq ':thumbsdown:'
- end
-
- it 'has an align attribute' do
- doc = filter(':8ball:')
- expect(doc.css('img').first.attr('align')).to eq 'absmiddle'
- end
-
- it 'unicode has an align attribute' do
- doc = filter("'🎱'")
- 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 'unicode has an emoji class' do
- doc = filter("'🐱'")
- 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 'unicode has height and width attributes' do
- doc = filter("'🐶'")
- img = doc.css('img').first
-
- expect(img.attr('width')).to eq '20'
- expect(img.attr('height')).to eq '20'
+ expect(doc.css('gl-emoji').first.attr('data-unicode-version')).to eq '6.0'
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/)
+ expect(doc.to_html).to match(/^This deserves a <gl-emoji.+>, big time\.\z/)
end
it 'unicode keeps whitespace intact' do
doc = filter('This deserves a 🎱, 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
-
- it 'uses a custom asset_root context' do
- root = Gitlab.config.gitlab.url + 'gitlab/root'
-
- doc = filter("'🎱'", 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("'🎱'", asset_host: 'https://this-is-ignored-i-guess?')
- expect(doc.css('img').first.attr('src')).to start_with('https://cdn.example.com')
+ expect(doc.to_html).to match(/^This deserves a <gl-emoji.+>, big time\.\z/)
end
end
diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
index fe2ce092e6b..082c0d4dd0d 100644
--- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
+++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::GollumTagsFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:user) { double }
let(:project_wiki) { ProjectWiki.new(project, user) }
diff --git a/spec/lib/banzai/filter/image_link_filter_spec.rb b/spec/lib/banzai/filter/image_link_filter_spec.rb
index a2a1ed58d1b..294558b3db2 100644
--- a/spec/lib/banzai/filter/image_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/image_link_filter_spec.rb
@@ -13,8 +13,8 @@ describe Banzai::Filter::ImageLinkFilter, lib: true do
end
it 'does not wrap a duplicate link' do
- exp = act = %q(<a href="/whatever">#{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')}</a>)
- expect(filter(act).to_html).to eq exp
+ doc = filter(%Q(<a href="/whatever">#{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')}</a>))
+ expect(doc.to_html).to match /^<a href="\/whatever"><img[^>]*><\/a>$/
end
it 'works with external images' do
@@ -22,8 +22,8 @@ describe Banzai::Filter::ImageLinkFilter, lib: true do
expect(doc.at_css('img')['src']).to eq doc.at_css('a')['href']
end
- it 'wraps the image with a link and a div' do
- doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.to_html).to include('<div class="image-container">')
+ it 'works with inline images' do
+ doc = filter(%Q(<p>test #{image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')} inline</p>))
+ expect(doc.to_html).to match /^<p>test <a[^>]*><img[^>]*><\/a> inline<\/p>$/
end
end
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 456dbac0698..f1082495fcc 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -21,6 +21,19 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
end
end
+ describe 'performance' do
+ let(:another_issue) { create(:issue, project: project) }
+
+ it 'does not have a N+1 query problem' do
+ single_reference = "Issue #{issue.to_reference}"
+ multiple_references = "Issues #{issue.to_reference} and #{another_issue.to_reference}"
+
+ control_count = ActiveRecord::QueryRecorder.new { reference_filter(single_reference).to_html }.count
+
+ expect { reference_filter(multiple_references).to_html }.not_to exceed_query_limit(control_count)
+ end
+ end
+
context 'internal reference' do
it_behaves_like 'a reference containing an element node'
@@ -311,7 +324,7 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
end
end
- describe '#issues_per_Project' do
+ describe '#issues_per_project' do
context 'using an internal issue tracker' do
it 'returns a Hash containing the issues per project' do
doc = Nokogiri::HTML.fragment('')
@@ -346,4 +359,26 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
end
end
end
+
+ describe '.references_in' do
+ let(:merge_request) { create(:merge_request) }
+
+ it 'yields valid references' do
+ expect do |b|
+ described_class.references_in(issue.to_reference, &b)
+ end.to yield_with_args(issue.to_reference, issue.iid, nil, nil, MatchData)
+ end
+
+ it "doesn't yield invalid references" do
+ expect do |b|
+ described_class.references_in('#0', &b)
+ end.not_to yield_control
+ end
+
+ it "doesn't yield unsupported references" do
+ expect do |b|
+ described_class.references_in(merge_request.to_reference, &b)
+ end.not_to yield_control
+ 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
index 275010c1a2c..40232f6e426 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -17,6 +17,19 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
end
end
+ describe 'performance' do
+ let(:another_merge) { create(:merge_request, source_project: project, source_branch: 'fix') }
+
+ it 'does not have a N+1 query problem' do
+ single_reference = "Merge request #{merge.to_reference}"
+ multiple_references = "Merge requests #{merge.to_reference} and #{another_merge.to_reference}"
+
+ control_count = ActiveRecord::QueryRecorder.new { reference_filter(single_reference).to_html }.count
+
+ expect { reference_filter(multiple_references).to_html }.not_to exceed_query_limit(control_count)
+ end
+ end
+
context 'internal reference' do
let(:reference) { merge.to_reference }
@@ -188,7 +201,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
context 'cross-project URL reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:merge) { create(:merge_request, source_project: project2, target_project: project2) }
let(:reference) { urls.namespace_project_merge_request_url(project2.namespace, project2, merge) + '/diffs#note_123' }
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 73b5edb99b3..a317c751d32 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) }
let(:reference) { milestone.to_reference }
diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb
new file mode 100644
index 00000000000..f85a5dcbd8b
--- /dev/null
+++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe Banzai::Filter::PlantumlFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'should replace plantuml pre tag with img tag' do
+ stub_application_setting(plantuml_enabled: true, plantuml_url: "http://localhost:8080")
+ input = '<pre class="plantuml"><code>Bob -> Sara : Hello</code><pre>'
+ output = '<div class="imageblock"><div class="content"><img class="plantuml" src="http://localhost:8080/png/U9npoazIqBLJ24uiIbImKl18pSd91m0rkGMq"></div></div>'
+ doc = filter(input)
+
+ expect(doc.to_s).to eq output
+ end
+
+ it 'should not replace plantuml pre tag with img tag if disabled' do
+ stub_application_setting(plantuml_enabled: false)
+ input = '<pre class="plantuml"><code>Bob -> Sara : Hello</code><pre>'
+ output = '<pre class="plantuml"><code>Bob -&gt; Sara : Hello</code><pre></pre></pre>'
+ doc = filter(input)
+
+ expect(doc.to_s).to eq output
+ end
+
+ it 'should not replace plantuml pre tag with img tag if url is invalid' do
+ stub_application_setting(plantuml_enabled: true, plantuml_url: "invalid")
+ input = '<pre class="plantuml"><code>Bob -> Sara : Hello</code><pre>'
+ output = '<div class="listingblock"><div class="content"><pre class="plantuml plantuml-error"> PlantUML Error: cannot connect to PlantUML server at "invalid"</pre></div></div>'
+ doc = filter(input)
+
+ expect(doc.to_s).to eq output
+ end
+end
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index df2dd173b57..1957ba739e2 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -25,7 +25,7 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do
%(<a href="#{path}">#{path}</a>)
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:project_path) { project.path_with_namespace }
let(:ref) { 'markdown' }
let(:commit) { project.commit(ref) }
diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb
index b38e3b17e64..b4cd5f63a15 100644
--- a/spec/lib/banzai/filter/sanitization_filter_spec.rb
+++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb
@@ -86,6 +86,16 @@ describe Banzai::Filter::SanitizationFilter, lib: true do
expect(filter(act).to_html).to eq exp
end
+ it 'allows `summary` elements' do
+ exp = act = '<summary>summary line</summary>'
+ expect(filter(act).to_html).to eq exp
+ end
+
+ it 'allows `details` elements' do
+ exp = act = '<details>long text goes here</details>'
+ 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>}
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index d265d29ee86..63fb1bb25c4 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -6,21 +6,21 @@ describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
context "when no language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code>def fun end</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" v-pre="true"><code>def fun end</code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre>')
end
end
context "when a valid language is specified" do
it "highlights as that language" do
result = filter('<pre><code class="ruby">def fun end</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" v-pre="true"><code><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre>')
end
end
context "when an invalid language is specified" do
it "highlights as plaintext" do
result = filter('<pre><code class="gnuplot">This is a test</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" v-pre="true"><code>This is a test</code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>')
end
end
@@ -31,7 +31,7 @@ describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
it "highlights as plaintext" do
result = filter('<pre><code class="ruby">This is a test</code></pre>')
- expect(result.to_html).to eq('<pre class="code highlight" v-pre="true"><code>This is a test</code></pre>')
+ expect(result.to_html).to eq('<pre class="code highlight" lang="" v-pre="true"><code>This is a test</code></pre>')
end
end
end
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
index 8b76c1d73c9..639cac6406a 100644
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb
@@ -29,7 +29,7 @@ describe Banzai::Filter::UploadLinkFilter, lib: true do
%(<div><a href="#{path}">#{path}</a></div>)
end
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
shared_examples :preserve_unchanged do
it 'does not modify any relative URL in anchor' do
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index 5bfeb82e738..63b23dac7ed 100644
--- a/spec/lib/banzai/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -83,6 +83,14 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
expect(doc.css('a').length).to eq 1
end
+ it 'links to a User with different case-sensitivity' do
+ user = create(:user, username: 'RescueRanger')
+
+ doc = reference_filter("Hey #{user.to_reference.upcase}")
+ expect(doc.css('a').length).to eq 1
+ expect(doc.css('a').text).to eq(user.to_reference)
+ end
+
it 'includes a data-user attribute' do
doc = reference_filter("Hey #{reference}")
link = doc.css('a').first
@@ -112,6 +120,25 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
end
end
+ context 'mentioning a nested group' do
+ it_behaves_like 'a reference containing an element node'
+
+ let(:group) { create(:group, :nested) }
+ let(:reference) { group.to_reference }
+
+ it 'links to the nested group' do
+ doc = reference_filter("Hey #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
+ end
+
+ it 'has the full group name as a title' do
+ doc = reference_filter("Hey #{reference}")
+
+ expect(doc.css('a').first.attr('title')).to eq group.full_name
+ end
+ end
+
it 'links with adjacent text' do
doc = reference_filter("Mention me (#{reference}.)")
expect(doc.to_html).to match(/\(<a.+>#{reference}<\/a>\.\)/)
@@ -152,6 +179,30 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do
end
end
+ context 'when a project is not specified' do
+ let(:project) { nil }
+
+ it 'does not link a User' do
+ doc = reference_filter("Hey #{reference}")
+
+ expect(doc).not_to include('a')
+ end
+
+ context 'when skip_project_check set to true' do
+ it 'links to a User' do
+ doc = reference_filter("Hey #{reference}", skip_project_check: true)
+
+ expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
+ end
+
+ it 'does not link users using @all reference' do
+ doc = reference_filter("Hey #{User.reference_prefix}all", skip_project_check: true)
+
+ expect(doc).not_to include('a')
+ end
+ end
+ end
+
describe '#namespaces' do
it 'returns a Hash containing all Namespaces' do
document = Nokogiri::HTML.fragment("<p>#{user.to_reference}</p>")
diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb
index 6ab1be9ccb7..00494f545a3 100644
--- a/spec/lib/banzai/filter/video_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/video_link_filter_spec.rb
@@ -13,7 +13,7 @@ describe Banzai::Filter::VideoLinkFilter, lib: true do
%(<img src="#{path}" />)
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context 'when the element src has a video extension' do
UploaderHelper::VIDEO_EXT.each do |ext|
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index fafc2cec546..31ca9d27b0b 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -147,7 +147,7 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
describe '#nodes_user_can_reference' do
context 'when the link has a data-author attribute' do
it 'returns the nodes when the user is a member of the project' do
- other_project = create(:project)
+ other_project = create(:empty_project)
other_project.team << [user, :developer]
link['data-project'] = other_project.id.to_s
@@ -164,7 +164,7 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
end
it 'returns an empty Array when the user could not be found' do
- other_project = create(:project)
+ other_project = create(:empty_project)
link['data-project'] = other_project.id.to_s
link['data-author'] = ''
@@ -173,7 +173,7 @@ describe Banzai::ReferenceParser::UserParser, lib: true do
end
it 'returns an empty Array when the user is not a team member' do
- other_project = create(:project)
+ other_project = create(:empty_project)
link['data-project'] = other_project.id.to_s
link['data-author'] = user.id.to_s
diff --git a/spec/lib/bitbucket/collection_spec.rb b/spec/lib/bitbucket/collection_spec.rb
index 015a7f80e03..9008cb3e870 100644
--- a/spec/lib/bitbucket/collection_spec.rb
+++ b/spec/lib/bitbucket/collection_spec.rb
@@ -19,6 +19,6 @@ describe Bitbucket::Collection do
it "iterates paginator" do
collection = described_class.new(TestPaginator.new)
- expect(collection.to_a).to match(["result_1_page_1", "result_2_page_1", "result_1_page_2", "result_2_page_2"])
+ expect(collection.to_a).to match(%w(result_1_page_1 result_2_page_1 result_1_page_2 result_2_page_2))
end
end
diff --git a/spec/lib/bitbucket/representation/repo_spec.rb b/spec/lib/bitbucket/representation/repo_spec.rb
index adcd978e1b3..405265cc669 100644
--- a/spec/lib/bitbucket/representation/repo_spec.rb
+++ b/spec/lib/bitbucket/representation/repo_spec.rb
@@ -29,7 +29,7 @@ describe Bitbucket::Representation::Repo do
end
describe '#owner_and_slug' do
- it { expect(described_class.new({ 'full_name' => 'ben/test' }).owner_and_slug).to eq(['ben', 'test']) }
+ it { expect(described_class.new({ 'full_name' => 'ben/test' }).owner_and_slug).to eq(%w(ben test)) }
end
describe '#owner' do
@@ -42,7 +42,7 @@ describe Bitbucket::Representation::Repo do
describe '#clone_url' do
it 'builds url' do
- data = { 'links' => { 'clone' => [ { 'name' => 'https', 'href' => 'https://bibucket.org/test/test.git' }] } }
+ data = { 'links' => { 'clone' => [{ 'name' => 'https', 'href' => 'https://bibucket.org/test/test.git' }] } }
expect(described_class.new(data).clone_url('abc')).to eq('https://x-token-auth:abc@bibucket.org/test/test.git')
end
end
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index f824e2e1efe..53abc056602 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -4,6 +4,84 @@ module Ci
describe GitlabCiYamlProcessor, lib: true do
let(:path) { 'path' }
+ describe 'our current .gitlab-ci.yml' do
+ let(:config) { File.read("#{Rails.root}/.gitlab-ci.yml") }
+
+ it 'is valid' do
+ error_message = described_class.validation_message(config)
+
+ expect(error_message).to be_nil
+ end
+ end
+
+ describe '#build_attributes' do
+ subject { described_class.new(config, path).build_attributes(:rspec) }
+
+ describe 'coverage entry' do
+ describe 'code coverage regexp' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec',
+ coverage: '/Code coverage: \d+\.\d+/' })
+ end
+
+ it 'includes coverage regexp in build attributes' do
+ expect(subject)
+ .to include(coverage_regex: 'Code coverage: \d+\.\d+')
+ end
+ end
+ end
+
+ describe 'allow failure entry' do
+ context 'when job is a manual action' do
+ context 'when allow_failure is defined' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec',
+ when: 'manual',
+ allow_failure: false })
+ end
+
+ it 'is not allowed to fail' do
+ expect(subject[:allow_failure]).to be false
+ end
+ end
+
+ context 'when allow_failure is not defined' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec',
+ when: 'manual' })
+ end
+
+ it 'is allowed to fail' do
+ expect(subject[:allow_failure]).to be true
+ end
+ end
+ end
+
+ context 'when job is not a manual action' do
+ context 'when allow_failure is defined' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec',
+ allow_failure: false })
+ end
+
+ it 'is not allowed to fail' do
+ expect(subject[:allow_failure]).to be false
+ end
+ end
+
+ context 'when allow_failure is not defined' do
+ let(:config) do
+ YAML.dump(rspec: { script: 'rspec' })
+ end
+
+ it 'is not allowed to fail' do
+ expect(subject[:allow_failure]).to be false
+ end
+ end
+ end
+ end
+ end
+
describe "#builds_for_ref" do
let(:type) { 'test' }
@@ -21,6 +99,7 @@ module Ci
stage_idx: 1,
name: "rspec",
commands: "pwd\nrspec",
+ coverage_regex: nil,
tag_list: [],
options: {},
allow_failure: false,
@@ -67,7 +146,7 @@ module Ci
it "returns builds if only has a list of branches including specified" do
config = YAML.dump({
before_script: ["pwd"],
- rspec: { script: "rspec", type: type, only: ["master", "deploy"] }
+ rspec: { script: "rspec", type: type, only: %w(master deploy) }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
@@ -144,8 +223,8 @@ module Ci
it "returns build only for specified type" do
config = YAML.dump({
before_script: ["pwd"],
- rspec: { script: "rspec", type: "test", only: ["master", "deploy"] },
- staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] },
+ rspec: { script: "rspec", type: "test", only: %w(master deploy) },
+ staging: { script: "deploy", type: "deploy", only: %w(master deploy) },
production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] },
})
@@ -223,7 +302,7 @@ module Ci
it "does not return builds if except has a list of branches including specified" do
config = YAML.dump({
before_script: ["pwd"],
- rspec: { script: "rspec", type: type, except: ["master", "deploy"] }
+ rspec: { script: "rspec", type: type, except: %w(master deploy) }
})
config_processor = GitlabCiYamlProcessor.new(config, path)
@@ -435,6 +514,7 @@ module Ci
stage_idx: 1,
name: "rspec",
commands: "pwd\nrspec",
+ coverage_regex: nil,
tag_list: [],
options: {
image: "ruby:2.1",
@@ -463,6 +543,7 @@ module Ci
stage_idx: 1,
name: "rspec",
commands: "pwd\nrspec",
+ coverage_regex: nil,
tag_list: [],
options: {
image: "ruby:2.5",
@@ -549,7 +630,7 @@ module Ci
context 'when syntax is incorrect' do
context 'when variables defined but invalid' do
let(:variables) do
- [ 'VAR1', 'value1', 'VAR2', 'value2' ]
+ %w(VAR1 value1 VAR2 value2)
end
it 'raises error' do
@@ -702,6 +783,7 @@ module Ci
stage_idx: 1,
name: "rspec",
commands: "pwd\nrspec",
+ coverage_regex: nil,
tag_list: [],
options: {
image: "ruby:2.1",
@@ -877,7 +959,7 @@ module Ci
end
context 'dependencies to builds' do
- let(:dependencies) { ['build1', 'build2'] }
+ let(:dependencies) { %w(build1 build2) }
it { expect { subject }.not_to raise_error }
end
@@ -913,6 +995,7 @@ module Ci
stage_idx: 1,
name: "normal_job",
commands: "test",
+ coverage_regex: nil,
tag_list: [],
options: {},
when: "on_success",
@@ -958,6 +1041,7 @@ module Ci
stage_idx: 0,
name: "job1",
commands: "execute-script-for-job",
+ coverage_regex: nil,
tag_list: [],
options: {},
when: "on_success",
@@ -970,6 +1054,7 @@ module Ci
stage_idx: 0,
name: "job2",
commands: "execute-script-for-job",
+ coverage_regex: nil,
tag_list: [],
options: {},
when: "on_success",
@@ -1180,7 +1265,7 @@ EOT
end
it "returns errors if job stage is not a defined stage" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", type: "acceptance" } })
+ config = YAML.dump({ types: %w(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")
@@ -1222,42 +1307,42 @@ EOT
end
it "returns errors if job artifacts:name is not an a string" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { name: 1 } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { name: 1 } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:artifacts name should be a string")
end
it "returns errors if job artifacts:when is not an a predefined value" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { when: 1 } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { when: 1 } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:artifacts when should be on_success, on_failure or always")
end
it "returns errors if job artifacts:expire_in is not an a string" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { expire_in: 1 } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { expire_in: 1 } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:artifacts expire in should be a duration")
end
it "returns errors if job artifacts:expire_in is not an a valid duration" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:artifacts expire in should be a duration")
end
it "returns errors if job artifacts:untracked is not an array of strings" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { untracked: "string" } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { untracked: "string" } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:artifacts untracked should be a boolean value")
end
it "returns errors if job artifacts:paths is not an array of strings" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { paths: "string" } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { paths: "string" } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:artifacts paths should be an array of strings")
@@ -1285,28 +1370,28 @@ EOT
end
it "returns errors if job cache:key is not an a string" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { key: 1 } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: 1 } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:cache:key config should be a string or symbol")
end
it "returns errors if job cache:untracked is not an array of strings" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { untracked: "string" } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { untracked: "string" } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:cache:untracked config should be a boolean value")
end
it "returns errors if job cache:paths is not an array of strings" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { paths: "string" } } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { paths: "string" } } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:cache:paths config should be an array of strings")
end
it "returns errors if job dependencies is not an array of strings" do
- config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", dependencies: "string" } })
+ config = YAML.dump({ types: %w(build test), rspec: { script: "test", dependencies: "string" } })
expect do
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec dependencies should be an array of strings")
diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb
index 94266f6653b..4f25ad88960 100644
--- a/spec/lib/constraints/project_url_constrainer_spec.rb
+++ b/spec/lib/constraints/project_url_constrainer_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
describe ProjectUrlConstrainer, lib: true do
- let!(:project) { create(:project) }
+ let!(:project) { create(:empty_project) }
let!(:namespace) { project.namespace }
describe '#matches?' do
context 'valid request' do
- let(:request) { build_request(namespace.path, project.path) }
+ let(:request) { build_request(namespace.full_path, project.path) }
it { expect(subject.matches?(request)).to be_truthy }
end
@@ -19,7 +19,7 @@ describe ProjectUrlConstrainer, lib: true do
end
context "project id ending with .git" do
- let(:request) { build_request(namespace.path, project.path + '.git') }
+ let(:request) { build_request(namespace.full_path, project.path + '.git') }
it { expect(subject.matches?(request)).to be_falsey }
end
diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb
index ec2f66b1136..d70690f589d 100644
--- a/spec/lib/event_filter_spec.rb
+++ b/spec/lib/event_filter_spec.rb
@@ -3,17 +3,17 @@ require 'spec_helper'
describe EventFilter, lib: true do
describe '#apply_filter' do
let(:source_user) { create(:user) }
- let!(:public_project) { create(:project, :public) }
-
- let!(:push_event) { create(:event, action: Event::PUSHED, project: public_project, target: public_project, author: source_user) }
- let!(:merged_event) { create(:event, action: Event::MERGED, project: public_project, target: public_project, author: source_user) }
- let!(:created_event) { create(:event, action: Event::CREATED, project: public_project, target: public_project, author: source_user) }
- let!(:updated_event) { create(:event, action: Event::UPDATED, project: public_project, target: public_project, author: source_user) }
- let!(:closed_event) { create(:event, action: Event::CLOSED, project: public_project, target: public_project, author: source_user) }
- let!(:reopened_event) { create(:event, action: Event::REOPENED, project: public_project, target: public_project, author: source_user) }
- let!(:comments_event) { create(:event, action: Event::COMMENTED, project: public_project, target: public_project, author: source_user) }
- let!(:joined_event) { create(:event, action: Event::JOINED, project: public_project, target: public_project, author: source_user) }
- let!(:left_event) { create(:event, action: Event::LEFT, project: public_project, target: public_project, author: source_user) }
+ let!(:public_project) { create(:empty_project, :public) }
+
+ let!(:push_event) { create(:event, :pushed, project: public_project, target: public_project, author: source_user) }
+ let!(:merged_event) { create(:event, :merged, project: public_project, target: public_project, author: source_user) }
+ let!(:created_event) { create(:event, :created, project: public_project, target: public_project, author: source_user) }
+ let!(:updated_event) { create(:event, :updated, project: public_project, target: public_project, author: source_user) }
+ let!(:closed_event) { create(:event, :closed, project: public_project, target: public_project, author: source_user) }
+ let!(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project, author: source_user) }
+ let!(:comments_event) { create(:event, :commented, project: public_project, target: public_project, author: source_user) }
+ let!(:joined_event) { create(:event, :joined, project: public_project, target: public_project, author: source_user) }
+ let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) }
it 'applies push filter' do
events = EventFilter.new(EventFilter.push).apply_filter(Event.all)
diff --git a/spec/lib/expand_variables_spec.rb b/spec/lib/expand_variables_spec.rb
index 90bc7dad379..90628917943 100644
--- a/spec/lib/expand_variables_spec.rb
+++ b/spec/lib/expand_variables_spec.rb
@@ -7,58 +7,49 @@ describe ExpandVariables do
tests = [
{ value: 'key',
result: 'key',
- variables: []
- },
+ variables: [] },
{ value: 'key$variable',
result: 'key',
- variables: []
- },
+ variables: [] },
{ value: 'key$variable',
result: 'keyvalue',
variables: [
{ key: 'variable', value: 'value' }
- ]
- },
+ ] },
{ value: 'key${variable}',
result: 'keyvalue',
variables: [
{ key: 'variable', value: 'value' }
- ]
- },
+ ] },
{ value: 'key$variable$variable2',
result: 'keyvalueresult',
variables: [
{ key: 'variable', value: 'value' },
{ key: 'variable2', value: 'result' },
- ]
- },
+ ] },
{ value: 'key${variable}${variable2}',
result: 'keyvalueresult',
variables: [
{ key: 'variable', value: 'value' },
{ key: 'variable2', value: 'result' }
- ]
- },
+ ] },
{ value: 'key$variable2$variable',
result: 'keyresultvalue',
variables: [
{ key: 'variable', value: 'value' },
{ key: 'variable2', value: 'result' },
- ]
- },
+ ] },
{ value: 'key${variable2}${variable}',
result: 'keyresultvalue',
variables: [
{ key: 'variable', value: 'value' },
{ key: 'variable2', value: 'result' }
- ]
- },
- { value: 'review/$CI_BUILD_REF_NAME',
+ ] },
+ { value: 'review/$CI_COMMIT_REF_NAME',
result: 'review/feature/add-review-apps',
variables: [
- { key: 'CI_BUILD_REF_NAME', value: 'feature/add-review-apps' }
- ]
- },
+ { key: 'CI_COMMIT_REF_NAME', value: 'feature/add-review-apps' }
+ ] },
]
tests.each do |test|
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index 0e85e302f29..33ab005667a 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -24,7 +24,7 @@ describe ExtractsPath, lib: true do
let(:params) { { path: sample_commit[:line_code_path], ref: ref } }
before do
- @project = create(:project)
+ @project = create(:project, :repository)
end
it "log tree path has no escape sequences" do
@@ -177,12 +177,12 @@ describe ExtractsPath, lib: true do
it "extracts a valid commit SHA" do
expect(extract_ref('f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG')).to eq(
- ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
+ %w(f4b14494ef6abf3d144c28e4af0c20143383e062 CHANGELOG)
)
end
it "falls back to a primitive split for an invalid ref" do
- expect(extract_ref('stable/CHANGELOG')).to eq(['stable', 'CHANGELOG'])
+ expect(extract_ref('stable/CHANGELOG')).to eq(%w(stable CHANGELOG))
end
end
end
diff --git a/spec/lib/git_ref_validator_spec.rb b/spec/lib/git_ref_validator_spec.rb
index dc57e94f193..cc8daa535d6 100644
--- a/spec/lib/git_ref_validator_spec.rb
+++ b/spec/lib/git_ref_validator_spec.rb
@@ -5,6 +5,7 @@ describe Gitlab::GitRefValidator, lib: true do
it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy }
it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy }
it { expect(Gitlab::GitRefValidator.validate('#1')).to be_truthy }
+ it { expect(Gitlab::GitRefValidator.validate('feature/refs/heads/foo')).to be_truthy }
it { expect(Gitlab::GitRefValidator.validate('feature/~new/')).to be_falsey }
it { expect(Gitlab::GitRefValidator.validate('feature/^new/')).to be_falsey }
it { expect(Gitlab::GitRefValidator.validate('feature/:new/')).to be_falsey }
@@ -17,4 +18,8 @@ describe Gitlab::GitRefValidator, lib: true do
it { expect(Gitlab::GitRefValidator.validate('feature\new')).to be_falsey }
it { expect(Gitlab::GitRefValidator.validate('feature//new')).to be_falsey }
it { expect(Gitlab::GitRefValidator.validate('feature new')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('refs/heads/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('refs/remotes/')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('refs/heads/feature')).to be_falsey }
+ it { expect(Gitlab::GitRefValidator.validate('refs/remotes/origin')).to be_falsey }
end
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index ba199917f5c..bca57105d1d 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -41,6 +41,29 @@ module Gitlab
render(input, context, asciidoc_opts)
end
end
+
+ context "XSS" do
+ links = {
+ 'links' => {
+ input: 'link:mylink"onmouseover="alert(1)[Click Here]',
+ output: "<div>\n<p><a href=\"mylink\">Click Here</a></p>\n</div>"
+ },
+ 'images' => {
+ input: 'image:https://localhost.com/image.png[Alt text" onerror="alert(7)]',
+ output: "<div>\n<p><span><img src=\"https://localhost.com/image.png\" alt=\"Alt text\"></span></p>\n</div>"
+ },
+ 'pre' => {
+ input: '```mypre"><script>alert(3)</script>',
+ output: "<div>\n<div>\n<pre lang=\"mypre\">\"&gt;<code></code></pre>\n</div>\n</div>"
+ }
+ }
+
+ links.each do |name, data|
+ it "does not convert dangerous #{name} into HTML" do
+ expect(render(data[:input], context)).to eql data[:output]
+ end
+ end
+ end
end
def render(*args)
diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
new file mode 100644
index 00000000000..94dcddcc30c
--- /dev/null
+++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+describe Gitlab::Auth::UniqueIpsLimiter, :redis, lib: true do
+ include_context 'unique ips sign in limit'
+ let(:user) { create(:user) }
+
+ describe '#count_unique_ips' do
+ context 'non unique IPs' do
+ it 'properly counts them' do
+ expect(described_class.update_and_return_ips_count(user.id, 'ip1')).to eq(1)
+ expect(described_class.update_and_return_ips_count(user.id, 'ip1')).to eq(1)
+ end
+ end
+
+ context 'unique IPs' do
+ it 'properly counts them' do
+ expect(described_class.update_and_return_ips_count(user.id, 'ip2')).to eq(1)
+ expect(described_class.update_and_return_ips_count(user.id, 'ip3')).to eq(2)
+ end
+ end
+
+ it 'resets count after specified time window' do
+ Timecop.freeze do
+ expect(described_class.update_and_return_ips_count(user.id, 'ip2')).to eq(1)
+ expect(described_class.update_and_return_ips_count(user.id, 'ip3')).to eq(2)
+
+ Timecop.travel(Time.now.utc + described_class.config.unique_ips_limit_time_window) do
+ expect(described_class.update_and_return_ips_count(user.id, 'ip4')).to eq(1)
+ expect(described_class.update_and_return_ips_count(user.id, 'ip5')).to eq(2)
+ end
+ end
+ end
+ end
+
+ describe '#limit_user!' do
+ include_examples 'user login operation with unique ip limit' do
+ def operation
+ described_class.limit_user! { user }
+ end
+ end
+
+ context 'allow 2 unique ips' do
+ before { current_application_settings.update!(unique_ips_limit_per_user: 2) }
+
+ it 'blocks user trying to login from third ip' do
+ change_ip('ip1')
+ expect(described_class.limit_user! { user }).to eq(user)
+
+ change_ip('ip2')
+ expect(described_class.limit_user! { user }).to eq(user)
+
+ change_ip('ip3')
+ expect { described_class.limit_user! { user } }.to raise_error(Gitlab::Auth::TooManyIps)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index f251c0dd25a..03c4879ed6f 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -3,6 +3,24 @@ require 'spec_helper'
describe Gitlab::Auth, lib: true do
let(:gl_auth) { described_class }
+ describe 'constants' do
+ it 'API_SCOPES contains all scopes for API access' do
+ expect(subject::API_SCOPES).to eq [:api, :read_user]
+ end
+
+ it 'OPENID_SCOPES contains all scopes for OpenID Connect' do
+ expect(subject::OPENID_SCOPES).to eq [:openid]
+ end
+
+ it 'DEFAULT_SCOPES contains all default scopes' do
+ expect(subject::DEFAULT_SCOPES).to eq [:api]
+ end
+
+ it 'OPTIONAL_SCOPES contains all non-default scopes' do
+ expect(subject::OPTIONAL_SCOPES).to eq [:read_user, :openid]
+ end
+ end
+
describe 'find_for_git_client' do
context 'build token' do
subject { gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: project, ip: 'ip') }
@@ -58,57 +76,121 @@ describe Gitlab::Auth, lib: true do
expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
end
- it 'recognizes user lfs tokens' do
- user = create(:user)
- token = Gitlab::LfsToken.new(user).token
+ include_examples 'user login operation with unique ip limit' do
+ let(:user) { create(:user, password: 'password') }
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.username)
- expect(gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :lfs_token, full_authentication_abilities))
+ def operation
+ expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
+ end
end
- it 'recognizes deploy key lfs tokens' do
- key = create(:deploy_key)
- token = Gitlab::LfsToken.new(key).token
+ context 'while using LFS authenticate' do
+ it 'recognizes user lfs tokens' do
+ user = create(:user)
+ token = Gitlab::LfsToken.new(user).token
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
- expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities))
- end
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.username)
+ expect(gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :lfs_token, full_authentication_abilities))
+ end
- context "while using OAuth tokens as passwords" do
- it 'succeeds for OAuth tokens with the `api` scope' do
+ it 'recognizes deploy key lfs tokens' do
+ key = create(:deploy_key)
+ token = Gitlab::LfsToken.new(key).token
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}")
+ expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities))
+ end
+
+ it 'does not try password auth before oauth' do
user = create(:user)
- application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user)
- token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api")
+ token = Gitlab::LfsToken.new(user).token
+
+ expect(gl_auth).not_to receive(:find_with_user_password)
+
+ gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')
+ end
+ end
+
+ context 'while using OAuth tokens as passwords' do
+ let(:user) { create(:user) }
+ let(:token_w_api_scope) { Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'api') }
+ let(:application) { Doorkeeper::Application.create!(name: 'MyApp', redirect_uri: 'https://app.com', owner: user) }
+ it 'succeeds for OAuth tokens with the `api` scope' do
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'oauth2')
- expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities))
+ expect(gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities))
end
it 'fails for OAuth tokens with other scopes' do
- user = create(:user)
- application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user)
- token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "read_user")
+ token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'read_user')
expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'oauth2')
expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
end
+
+ it 'does not try password auth before oauth' do
+ expect(gl_auth).not_to receive(:find_with_user_password)
+
+ gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')
+ end
end
- context "while using personal access tokens as passwords" do
+ context 'while using personal access tokens as passwords' do
it 'succeeds for personal access tokens with the `api` scope' do
- user = create(:user)
- personal_access_token = create(:personal_access_token, user: user, scopes: ['api'])
+ personal_access_token = create(:personal_access_token, scopes: ['api'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(personal_access_token.user, nil, :personal_token, full_authentication_abilities))
+ end
+
+ it 'succeeds if it is an impersonation token' do
+ impersonation_token = create(:personal_access_token, :impersonation, scopes: ['api'])
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.email)
- expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities))
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: '')
+ expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(impersonation_token.user, nil, :personal_token, full_authentication_abilities))
end
it 'fails for personal access tokens with other scopes' do
- user = create(:user)
- personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
+ personal_access_token = create(:personal_access_token, scopes: ['read_user'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
+ expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ end
+
+ it 'fails for impersonation token with other scopes' do
+ impersonation_token = create(:personal_access_token, scopes: ['read_user'])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
+ expect(gl_auth.find_for_git_client('', impersonation_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ end
+
+ it 'fails if password is nil' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: '')
+ expect(gl_auth.find_for_git_client('', nil, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ end
+ end
+
+ context 'while using regular user and password' do
+ it 'falls through lfs authentication' do
+ user = create(
+ :user,
+ username: 'normal_user',
+ password: 'my-secret',
+ )
- expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: user.email)
- expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil))
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
+ .to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
+ end
+
+ it 'falls through oauth authentication when the username is oauth2' do
+ user = create(
+ :user,
+ username: 'oauth2',
+ password: 'my-secret',
+ )
+
+ expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip'))
+ .to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities))
end
end
@@ -152,6 +234,24 @@ describe Gitlab::Auth, lib: true do
expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
end
+ include_examples 'user login operation with unique ip limit' do
+ def operation
+ expect(gl_auth.find_with_user_password(username, password)).to eq(user)
+ end
+ end
+
+ it "does not find user in blocked state" do
+ user.block
+
+ expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
+ end
+
+ it "does not find user in ldap_blocked state" do
+ user.ldap_block
+
+ expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
+ end
+
context "with ldap enabled" do
before do
allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true)
diff --git a/spec/lib/gitlab/award_emoji_spec.rb b/spec/lib/gitlab/award_emoji_spec.rb
deleted file mode 100644
index 00a110e31f8..00000000000
--- a/spec/lib/gitlab/award_emoji_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::AwardEmoji do
- describe '.urls' do
- after do
- Gitlab::AwardEmoji.instance_variable_set(:@urls, nil)
- end
-
- subject { Gitlab::AwardEmoji.urls }
-
- it { is_expected.to be_an_instance_of(Array) }
- it { is_expected.not_to be_empty }
-
- context 'every Hash in the Array' do
- it 'has the correct keys and values' do
- subject.each do |hash|
- expect(hash[:name]).to be_an_instance_of(String)
- expect(hash[:path]).to be_an_instance_of(String)
- end
- end
- end
-
- context 'handles relative root' do
- it 'includes the full path' do
- allow(Gitlab::Application.config).to receive(:relative_url_root).and_return('/gitlab')
-
- subject.each do |hash|
- expect(hash[:name]).to be_an_instance_of(String)
- expect(hash[:path]).to start_with('/gitlab')
- end
- end
- end
- end
-
- describe '.emoji_by_category' do
- it "only contains known categories" do
- undefined_categories = Gitlab::AwardEmoji.emoji_by_category.keys - Gitlab::AwardEmoji::CATEGORIES.keys
- expect(undefined_categories).to be_empty
- end
- end
-end
diff --git a/spec/lib/gitlab/badge/build/metadata_spec.rb b/spec/lib/gitlab/badge/build/metadata_spec.rb
index d678e522721..9df96ea04eb 100644
--- a/spec/lib/gitlab/badge/build/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/build/metadata_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
describe Gitlab::Badge::Build::Metadata do
- let(:badge) { double(project: create(:project), ref: 'feature') }
+ let(:badge) { double(project: create(:empty_project), ref: 'feature') }
let(:metadata) { described_class.new(badge) }
it_behaves_like 'badge metadata'
diff --git a/spec/lib/gitlab/badge/build/status_spec.rb b/spec/lib/gitlab/badge/build/status_spec.rb
index 70f03021d36..3c5414701a7 100644
--- a/spec/lib/gitlab/badge/build/status_spec.rb
+++ b/spec/lib/gitlab/badge/build/status_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Badge::Build::Status do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:sha) { project.commit.sha }
let(:branch) { 'master' }
let(:badge) { described_class.new(project, branch) }
diff --git a/spec/lib/gitlab/badge/coverage/metadata_spec.rb b/spec/lib/gitlab/badge/coverage/metadata_spec.rb
index 74eaf7eaf8b..5e93935ea37 100644
--- a/spec/lib/gitlab/badge/coverage/metadata_spec.rb
+++ b/spec/lib/gitlab/badge/coverage/metadata_spec.rb
@@ -3,7 +3,7 @@ require 'lib/gitlab/badge/shared/metadata'
describe Gitlab::Badge::Coverage::Metadata do
let(:badge) do
- double(project: create(:project), ref: 'feature', job: 'test')
+ double(project: create(:empty_project), ref: 'feature', job: 'test')
end
let(:metadata) { described_class.new(badge) }
diff --git a/spec/lib/gitlab/badge/shared/metadata.rb b/spec/lib/gitlab/badge/shared/metadata.rb
index 0cf18514251..63c7ca5a915 100644
--- a/spec/lib/gitlab/badge/shared/metadata.rb
+++ b/spec/lib/gitlab/badge/shared/metadata.rb
@@ -18,4 +18,14 @@ shared_examples 'badge metadata' do
it { is_expected.to include metadata.image_url }
it { is_expected.to include metadata.link_url }
end
+
+ describe '#to_asciidoc' do
+ subject { metadata.to_asciidoc }
+
+ it { is_expected.to include metadata.image_url }
+ it { is_expected.to include metadata.link_url }
+ it { is_expected.to include 'image:' }
+ it { is_expected.to include 'link=' }
+ it { is_expected.to include 'title=' }
+ end
end
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 72b1ba36b58..a7ee7f53a6b 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -52,7 +52,7 @@ describe Gitlab::BitbucketImport::Importer, lib: true do
let(:project) do
create(
- :project,
+ :empty_project,
import_source: project_identifier,
import_data: ProjectImportData.new(credentials: data)
)
@@ -87,10 +87,10 @@ describe Gitlab::BitbucketImport::Importer, lib: true do
body: issues_statuses_sample_data.to_json)
stub_request(:get, "https://api.bitbucket.org/2.0/repositories/namespace/repo?pagelen=50&sort=created_on").
- with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization' => 'Bearer', 'User-Agent' => 'Faraday v0.9.2' }).
- to_return(status: 200,
- body: "",
- headers: {})
+ with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization' => 'Bearer', 'User-Agent' => 'Faraday v0.9.2' }).
+ to_return(status: 200,
+ body: "",
+ headers: {})
sample_issues_statuses.each_with_index do |issue, index|
stub_request(
diff --git a/spec/lib/gitlab/blame_spec.rb b/spec/lib/gitlab/blame_spec.rb
index 89245761b6f..26b1baf75be 100644
--- a/spec/lib/gitlab/blame_spec.rb
+++ b/spec/lib/gitlab/blame_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Blame, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:path) { 'files/ruby/popen.rb' }
let(:commit) { project.commit('master') }
let(:blob) { project.repository.blob_at(commit.id, path) }
diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb
index a2d84977f58..b6e924d67be 100644
--- a/spec/lib/gitlab/chat_commands/command_spec.rb
+++ b/spec/lib/gitlab/chat_commands/command_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'when no command is available' do
let(:params) { { text: 'issue show 1' } }
- let(:project) { create(:project, has_external_issue_tracker: true) }
+ let(:project) { create(:empty_project, has_external_issue_tracker: true) }
it 'displays 404 messages' do
expect(subject[:response_type]).to be(:ephemeral)
@@ -24,7 +24,7 @@ describe Gitlab::ChatCommands::Command, service: true do
it 'displays the help message' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to start_with('Available commands')
+ expect(subject[:text]).to start_with('Unknown command')
expect(subject[:text]).to match('/gitlab issue show')
end
end
@@ -34,47 +34,7 @@ describe Gitlab::ChatCommands::Command, service: true do
it 'rejects the actions' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to start_with('Whoops! That action is not allowed')
- end
- end
-
- context 'issue is successfully created' do
- let(:params) { { text: "issue create my new issue" } }
-
- before do
- project.team << [user, :master]
- end
-
- it 'presents the issue' do
- expect(subject[:text]).to match("my new issue")
- end
-
- it 'shows a link to the new issue' do
- expect(subject[:text]).to match(/\/issues\/\d+/)
- end
- end
-
- context 'searching for an issue' do
- let(:params) { { text: 'issue search find me' } }
- let!(:issue) { create(:issue, project: project, title: 'find me') }
-
- before do
- project.team << [user, :master]
- end
-
- context 'a single issue is found' do
- it 'presents the issue' do
- expect(subject[:text]).to match(issue.title)
- end
- end
-
- context 'multiple issues found' do
- let!(:issue2) { create(:issue, project: project, title: "someone find me") }
-
- it 'shows a link to the new issue' do
- expect(subject[:text]).to match(issue.title)
- expect(subject[:text]).to match(issue2.title)
- end
+ expect(subject[:text]).to start_with('Whoops! This action is not allowed')
end
end
@@ -90,7 +50,7 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'and user can not create deployment' do
it 'returns action' do
expect(subject[:response_type]).to be(:ephemeral)
- expect(subject[:text]).to start_with('Whoops! That action is not allowed')
+ expect(subject[:text]).to start_with('Whoops! This action is not allowed')
end
end
@@ -100,7 +60,7 @@ describe Gitlab::ChatCommands::Command, service: true do
end
it 'returns action' do
- expect(subject[:text]).to include('Deployment from staging to production started.')
+ expect(subject[:text]).to include('Deployment started from staging to production')
expect(subject[:response_type]).to be(:in_channel)
end
@@ -130,7 +90,7 @@ describe Gitlab::ChatCommands::Command, service: true do
context 'IssueCreate is triggered' do
let(:params) { { text: 'issue create my title' } }
- it { is_expected.to eq(Gitlab::ChatCommands::IssueCreate) }
+ it { is_expected.to eq(Gitlab::ChatCommands::IssueNew) }
end
context 'IssueSearch is triggered' do
diff --git a/spec/lib/gitlab/chat_commands/deploy_spec.rb b/spec/lib/gitlab/chat_commands/deploy_spec.rb
index bd8099c92da..b3358a32161 100644
--- a/spec/lib/gitlab/chat_commands/deploy_spec.rb
+++ b/spec/lib/gitlab/chat_commands/deploy_spec.rb
@@ -15,8 +15,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do
end
context 'if no environment is defined' do
- it 'returns nil' do
- expect(subject).to be_nil
+ it 'does not execute an action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("No action found to be executed")
end
end
@@ -26,8 +27,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do
let!(:deployment) { create(:deployment, environment: staging, deployable: build) }
context 'without actions' do
- it 'returns nil' do
- expect(subject).to be_nil
+ it 'does not execute an action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("No action found to be executed")
end
end
@@ -37,8 +39,8 @@ describe Gitlab::ChatCommands::Deploy, service: true do
end
it 'returns success result' do
- expect(subject.type).to eq(:success)
- expect(subject.message).to include('Deployment from staging to production started')
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject[:text]).to start_with('Deployment started from staging to production')
end
context 'when duplicate action exists' do
@@ -47,8 +49,8 @@ describe Gitlab::ChatCommands::Deploy, service: true do
end
it 'returns error' do
- expect(subject.type).to eq(:error)
- expect(subject.message).to include('Too many actions defined')
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq('Too many actions defined')
end
end
@@ -59,9 +61,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do
name: 'teardown', environment: 'production')
end
- it 'returns success result' do
- expect(subject.type).to eq(:success)
- expect(subject.message).to include('Deployment from staging to production started')
+ it 'returns the success message' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject[:text]).to start_with('Deployment started from staging to production')
end
end
end
diff --git a/spec/lib/gitlab/chat_commands/issue_create_spec.rb b/spec/lib/gitlab/chat_commands/issue_new_spec.rb
index 6c71e79ff6d..84c22328064 100644
--- a/spec/lib/gitlab/chat_commands/issue_create_spec.rb
+++ b/spec/lib/gitlab/chat_commands/issue_new_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::ChatCommands::IssueCreate, service: true do
+describe Gitlab::ChatCommands::IssueNew, service: true do
describe '#execute' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
@@ -18,7 +18,7 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
it 'creates the issue' do
expect { subject }.to change { project.issues.count }.by(1)
- expect(subject.title).to eq('bird is the word')
+ expect(subject[:response_type]).to be(:in_channel)
end
end
@@ -41,6 +41,16 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
expect { subject }.to change { project.issues.count }.by(1)
end
end
+
+ context 'issue cannot be created' do
+ let!(:issue) { create(:issue, project: project, title: 'bird is the word') }
+ let(:regex_match) { described_class.match("issue create #{'a' * 512}}") }
+
+ it 'displays the errors' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to match("- Title is too long")
+ end
+ end
end
describe '.match' do
diff --git a/spec/lib/gitlab/chat_commands/issue_search_spec.rb b/spec/lib/gitlab/chat_commands/issue_search_spec.rb
index 24c06a967fa..551ccb79a58 100644
--- a/spec/lib/gitlab/chat_commands/issue_search_spec.rb
+++ b/spec/lib/gitlab/chat_commands/issue_search_spec.rb
@@ -2,9 +2,9 @@ require 'spec_helper'
describe Gitlab::ChatCommands::IssueSearch, service: true do
describe '#execute' do
- let!(:issue) { create(:issue, title: 'find me') }
+ let!(:issue) { create(:issue, project: project, title: 'find me') }
let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') }
- let(:project) { issue.project }
+ let(:project) { create(:empty_project) }
let(:user) { issue.author }
let(:regex_match) { described_class.match("issue search find") }
@@ -14,7 +14,8 @@ describe Gitlab::ChatCommands::IssueSearch, service: true do
context 'when the user has no access' do
it 'only returns the open issues' do
- expect(subject).not_to include(confidential)
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to match("not found")
end
end
@@ -24,13 +25,14 @@ describe Gitlab::ChatCommands::IssueSearch, service: true do
end
it 'returns all results' do
- expect(subject).to include(confidential, issue)
+ expect(subject).to have_key(:attachments)
+ expect(subject[:text]).to eq("Here are the 2 issues I found:")
end
end
context 'without hits on the query' do
it 'returns an empty collection' do
- expect(subject).to be_empty
+ expect(subject[:text]).to match("not found")
end
end
end
diff --git a/spec/lib/gitlab/chat_commands/issue_show_spec.rb b/spec/lib/gitlab/chat_commands/issue_show_spec.rb
index 2eab73e49e5..1f20d0a44ce 100644
--- a/spec/lib/gitlab/chat_commands/issue_show_spec.rb
+++ b/spec/lib/gitlab/chat_commands/issue_show_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::ChatCommands::IssueShow, service: true do
describe '#execute' do
- let(:issue) { create(:issue) }
- let(:project) { issue.project }
+ let(:issue) { create(:issue, project: project) }
+ let(:project) { create(:empty_project) }
let(:user) { issue.author }
let(:regex_match) { described_class.match("issue show #{issue.iid}") }
@@ -16,15 +16,19 @@ describe Gitlab::ChatCommands::IssueShow, service: true do
end
context 'the issue exists' do
+ let(:title) { subject[:attachments].first[:title] }
+
it 'returns the issue' do
- expect(subject.iid).to be issue.iid
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(title).to start_with(issue.title)
end
context 'when its reference is given' do
let(:regex_match) { described_class.match("issue show #{issue.to_reference}") }
it 'shows the issue' do
- expect(subject.iid).to be issue.iid
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(title).to start_with(issue.title)
end
end
end
@@ -32,17 +36,24 @@ describe Gitlab::ChatCommands::IssueShow, service: true do
context 'the issue does not exist' do
let(:regex_match) { described_class.match("issue show 2343242") }
- it "returns nil" do
- expect(subject).to be_nil
+ it "returns not found" do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to match("not found")
end
end
end
- describe 'self.match' do
+ describe '.match' do
it 'matches the iid' do
match = described_class.match("issue show 123")
expect(match[:iid]).to eq("123")
end
+
+ it 'accepts a reference' do
+ match = described_class.match("issue show #{Issue.reference_prefix}123")
+
+ expect(match[:iid]).to eq("123")
+ end
end
end
diff --git a/spec/lib/gitlab/chat_commands/presenters/access_spec.rb b/spec/lib/gitlab/chat_commands/presenters/access_spec.rb
new file mode 100644
index 00000000000..ae41d75ab0c
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/presenters/access_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::Presenters::Access do
+ describe '#access_denied' do
+ subject { described_class.new.access_denied }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'displays an error message' do
+ expect(subject[:text]).to match("is not allowed")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+
+ describe '#not_found' do
+ subject { described_class.new.not_found }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'tells the user the resource was not found' do
+ expect(subject[:text]).to match("not found!")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+
+ describe '#authorize' do
+ context 'with an authorization URL' do
+ subject { described_class.new('http://authorize.me').authorize }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'tells the user to authorize' do
+ expect(subject[:text]).to match("connect your GitLab account")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+
+ context 'without authorization url' do
+ subject { described_class.new.authorize }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'tells the user to authorize' do
+ expect(subject[:text]).to match("Couldn't identify you")
+ expect(subject[:response_type]).to be(:ephemeral)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb
new file mode 100644
index 00000000000..dc2dd300072
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb
@@ -0,0 +1,47 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::Presenters::Deploy do
+ let(:build) { create(:ci_build) }
+
+ describe '#present' do
+ subject { described_class.new(build).present('staging', 'prod') }
+
+ it { is_expected.to have_key(:text) }
+ it { is_expected.to have_key(:response_type) }
+ it { is_expected.to have_key(:status) }
+ it { is_expected.not_to have_key(:attachments) }
+
+ it 'messages the channel of the deploy' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject[:text]).to start_with("Deployment started from staging to prod")
+ end
+ end
+
+ describe '#no_actions' do
+ subject { described_class.new(nil).no_actions }
+
+ it { is_expected.to have_key(:text) }
+ it { is_expected.to have_key(:response_type) }
+ it { is_expected.to have_key(:status) }
+ it { is_expected.not_to have_key(:attachments) }
+
+ it 'tells the user there is no action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("No action found to be executed")
+ end
+ end
+
+ describe '#too_many_actions' do
+ subject { described_class.new([]).too_many_actions }
+
+ it { is_expected.to have_key(:text) }
+ it { is_expected.to have_key(:response_type) }
+ it { is_expected.to have_key(:status) }
+ it { is_expected.not_to have_key(:attachments) }
+
+ it 'tells the user there is no action' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to eq("Too many actions defined")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb
new file mode 100644
index 00000000000..17fcdbc2452
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::Presenters::IssueNew do
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:attachment) { subject[:attachments].first }
+
+ subject { described_class.new(issue).present }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'shows the issue' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject).to have_key(:attachments)
+ expect(attachment[:title]).to start_with(issue.title)
+ end
+end
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb
new file mode 100644
index 00000000000..ec6d3e34a96
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::Presenters::IssueSearch do
+ let(:project) { create(:empty_project) }
+ let(:message) { subject[:text] }
+
+ before { create_list(:issue, 2, project: project) }
+
+ subject { described_class.new(project.issues).present }
+
+ it 'formats the message correct' do
+ is_expected.to have_key(:text)
+ is_expected.to have_key(:status)
+ is_expected.to have_key(:response_type)
+ is_expected.to have_key(:attachments)
+ end
+
+ it 'shows a list of results' do
+ expect(subject[:response_type]).to be(:ephemeral)
+
+ expect(message).to start_with("Here are the 2 issues I found")
+ end
+end
diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb
new file mode 100644
index 00000000000..3916fc704a4
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::Presenters::IssueShow do
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:attachment) { subject[:attachments].first }
+
+ subject { described_class.new(issue).present }
+
+ it { is_expected.to be_a(Hash) }
+
+ it 'shows the issue' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(subject).to have_key(:attachments)
+ expect(attachment[:title]).to start_with(issue.title)
+ end
+
+ context 'with upvotes' do
+ before do
+ create(:award_emoji, :upvote, awardable: issue)
+ end
+
+ it 'shows the upvote count' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(attachment[:text]).to start_with("**Open** · :+1: 1")
+ end
+ end
+
+ context 'with labels' do
+ let(:label) { create(:label, project: project, title: 'mep') }
+ let(:label1) { create(:label, project: project, title: 'mop') }
+
+ before do
+ issue.labels << [label, label1]
+ end
+
+ it 'shows the labels' do
+ labels = attachment[:fields].find { |f| f[:title] == 'Labels' }
+
+ expect(labels[:value]).to eq("mep, mop")
+ end
+ end
+
+ context 'confidential issue' do
+ let(:issue) { create(:issue, project: project) }
+
+ it 'shows an ephemeral response' do
+ expect(subject[:response_type]).to be(:in_channel)
+ expect(attachment[:text]).to start_with("**Open**")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb
index 98effecdbbc..e22f88b7a32 100644
--- a/spec/lib/gitlab/checks/change_access_spec.rb
+++ b/spec/lib/gitlab/checks/change_access_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
describe '#exec' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user_access) { Gitlab::UserAccess.new(user, project: project) }
let(:changes) do
{
@@ -12,8 +12,16 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
ref: 'refs/heads/master'
}
end
-
- subject { described_class.new(changes, project: project, user_access: user_access).exec }
+ let(:protocol) { 'ssh' }
+
+ subject do
+ described_class.new(
+ changes,
+ project: project,
+ user_access: user_access,
+ protocol: protocol
+ ).exec
+ end
before { allow(user_access).to receive(:can_do_action?).with(:push_code).and_return(true) }
diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb
index f6288011494..7a84bbebd02 100644
--- a/spec/lib/gitlab/checks/force_push_spec.rb
+++ b/spec/lib/gitlab/checks/force_push_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context "exit code checking" do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb
new file mode 100644
index 00000000000..382385dfd6b
--- /dev/null
+++ b/spec/lib/gitlab/ci/build/image_spec.rb
@@ -0,0 +1,67 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Build::Image do
+ let(:job) { create(:ci_build, :no_options) }
+
+ describe '#from_image' do
+ subject { described_class.from_image(job) }
+
+ context 'when image is defined in job' do
+ let(:image_name) { 'ruby:2.1' }
+ let(:job) { create(:ci_build, options: { image: image_name } ) }
+
+ it 'fabricates an object of the proper class' do
+ is_expected.to be_kind_of(described_class)
+ end
+
+ it 'populates fabricated object with the proper name attribute' do
+ expect(subject.name).to eq(image_name)
+ end
+
+ context 'when image name is empty' do
+ let(:image_name) { '' }
+
+ it 'does not fabricate an object' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'when image is not defined in job' do
+ it 'does not fabricate an object' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ describe '#from_services' do
+ subject { described_class.from_services(job) }
+
+ context 'when services are defined in job' do
+ let(:service_image_name) { 'postgres' }
+ let(:job) { create(:ci_build, options: { services: [service_image_name] }) }
+
+ it 'fabricates an non-empty array of objects' do
+ is_expected.to be_kind_of(Array)
+ is_expected.not_to be_empty
+ expect(subject.first.name).to eq(service_image_name)
+ end
+
+ context 'when service image name is empty' do
+ let(:service_image_name) { '' }
+
+ it 'fabricates an empty array' do
+ is_expected.to be_kind_of(Array)
+ is_expected.to be_empty
+ end
+ end
+ end
+
+ context 'when services are not defined in job' do
+ it 'fabricates an empty array' do
+ is_expected.to be_kind_of(Array)
+ is_expected.to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/build/step_spec.rb b/spec/lib/gitlab/ci/build/step_spec.rb
new file mode 100644
index 00000000000..49457b129e3
--- /dev/null
+++ b/spec/lib/gitlab/ci/build/step_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Build::Step do
+ let(:job) { create(:ci_build, :no_options, commands: "ls -la\ndate") }
+
+ describe '#from_commands' do
+ subject { described_class.from_commands(job) }
+
+ it 'fabricates an object' do
+ expect(subject.name).to eq(:script)
+ expect(subject.script).to eq(['ls -la', 'date'])
+ expect(subject.timeout).to eq(job.timeout)
+ expect(subject.when).to eq('on_success')
+ expect(subject.allow_failure).to be_falsey
+ end
+ end
+
+ describe '#from_after_script' do
+ subject { described_class.from_after_script(job) }
+
+ context 'when after_script is empty' do
+ it 'doesn not fabricate an object' do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'when after_script is not empty' do
+ let(:job) { create(:ci_build, options: { after_script: ['ls -la', 'date'] }) }
+
+ it 'fabricates an object' do
+ expect(subject.name).to eq(:after_script)
+ expect(subject.script).to eq(['ls -la', 'date'])
+ expect(subject.timeout).to eq(job.timeout)
+ expect(subject.when).to eq('always')
+ expect(subject.allow_failure).to be_truthy
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index 70a327c5183..2ed120f356a 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -24,6 +24,20 @@ describe Gitlab::Ci::Config::Entry::Cache do
expect(entry).to be_valid
end
end
+
+ context 'when key is missing' do
+ let(:config) do
+ { untracked: true,
+ paths: ['some/path/'] }
+ end
+
+ describe '#value' do
+ it 'sets key with the default' do
+ expect(entry.value[:key])
+ .to eq(Gitlab::Ci::Config::Entry::Key.default)
+ end
+ end
+ end
end
context 'when entry value is not correct' do
diff --git a/spec/lib/gitlab/ci/config/entry/commands_spec.rb b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
index b8b0825a1c7..afa4a089418 100644
--- a/spec/lib/gitlab/ci/config/entry/commands_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/commands_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::Ci::Config::Entry::Commands do
let(:entry) { described_class.new(config) }
context 'when entry config value is an array' do
- let(:config) { ['ls', 'pwd'] }
+ let(:config) { %w(ls pwd) }
describe '#value' do
it 'returns array of strings' do
diff --git a/spec/lib/gitlab/ci/config/entry/coverage_spec.rb b/spec/lib/gitlab/ci/config/entry/coverage_spec.rb
new file mode 100644
index 00000000000..4c6bd859552
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/entry/coverage_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::Entry::Coverage do
+ let(:entry) { described_class.new(config) }
+
+ describe 'validations' do
+ context "when entry config value doesn't have the surrounding '/'" do
+ let(:config) { 'Code coverage: \d+\.\d+' }
+
+ describe '#errors' do
+ subject { entry.errors }
+ it { is_expected.to include(/coverage config must be a regular expression/) }
+ end
+
+ describe '#valid?' do
+ subject { entry }
+ it { is_expected.not_to be_valid }
+ end
+ end
+
+ context "when entry config value has the surrounding '/'" do
+ let(:config) { '/Code coverage: \d+\.\d+/' }
+
+ describe '#value' do
+ subject { entry.value }
+ it { is_expected.to eq(config[1...-1]) }
+ end
+
+ describe '#errors' do
+ subject { entry.errors }
+ it { is_expected.to be_empty }
+ end
+
+ describe '#valid?' do
+ subject { entry }
+ it { is_expected.to be_valid }
+ end
+ end
+
+ context 'when entry value is not valid' do
+ let(:config) { '(malformed regexp' }
+
+ describe '#errors' do
+ subject { entry.errors }
+ it { is_expected.to include(/coverage config must be a regular expression/) }
+ end
+
+ describe '#valid?' do
+ subject { entry }
+ it { is_expected.not_to be_valid }
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
index 2adbed2154f..c330e609337 100644
--- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
@@ -151,8 +151,8 @@ describe Gitlab::Ci::Config::Entry::Environment do
context 'when variables are used for environment' do
let(:config) do
- { name: 'review/$CI_BUILD_REF_NAME',
- url: 'https://$CI_BUILD_REF_NAME.review.gitlab.com' }
+ { name: 'review/$CI_COMMIT_REF_NAME',
+ url: 'https://$CI_COMMIT_REF_NAME.review.gitlab.com' }
end
describe '#valid?' do
diff --git a/spec/lib/gitlab/ci/config/entry/factory_spec.rb b/spec/lib/gitlab/ci/config/entry/factory_spec.rb
index 00dad5d9591..8dd48e4efae 100644
--- a/spec/lib/gitlab/ci/config/entry/factory_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/factory_spec.rb
@@ -8,20 +8,20 @@ describe Gitlab::Ci::Config::Entry::Factory do
context 'when setting a concrete value' do
it 'creates entry with valid value' do
entry = factory
- .value(['ls', 'pwd'])
+ .value(%w(ls pwd))
.create!
- expect(entry.value).to eq ['ls', 'pwd']
+ expect(entry.value).to eq %w(ls pwd)
end
context 'when setting description' do
it 'creates entry with description' do
entry = factory
- .value(['ls', 'pwd'])
+ .value(%w(ls pwd))
.with(description: 'test description')
.create!
- expect(entry.value).to eq ['ls', 'pwd']
+ expect(entry.value).to eq %w(ls pwd)
expect(entry.description).to eq 'test description'
end
end
@@ -29,7 +29,7 @@ describe Gitlab::Ci::Config::Entry::Factory do
context 'when setting key' do
it 'creates entry with custom key' do
entry = factory
- .value(['ls', 'pwd'])
+ .value(%w(ls pwd))
.with(key: 'test key')
.create!
@@ -60,13 +60,13 @@ describe Gitlab::Ci::Config::Entry::Factory do
end
context 'when creating entry with nil value' do
- it 'creates an undefined entry' do
+ it 'creates an unspecified entry' do
entry = factory
.value(nil)
.create!
expect(entry)
- .to be_an_instance_of Gitlab::Ci::Config::Entry::Unspecified
+ .not_to be_specified
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/global_spec.rb b/spec/lib/gitlab/ci/config/entry/global_spec.rb
index e64c8d46bd8..684d01e9056 100644
--- a/spec/lib/gitlab/ci/config/entry/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/global_spec.rb
@@ -4,24 +4,29 @@ describe Gitlab::Ci::Config::Entry::Global do
let(:global) { described_class.new(hash) }
describe '.nodes' do
- it 'can contain global config keys' do
- expect(described_class.nodes).to include :before_script
+ it 'returns a hash' do
+ expect(described_class.nodes).to be_a(Hash)
end
- it 'returns a hash' do
- expect(described_class.nodes).to be_a Hash
+ context 'when filtering all the entry/node names' do
+ it 'contains the expected node names' do
+ expect(described_class.nodes.keys)
+ .to match_array(%i[before_script image services
+ after_script variables stages
+ types cache])
+ end
end
end
context 'when configuration is valid' do
context 'when some entries defined' do
let(:hash) do
- { before_script: ['ls', 'pwd'],
+ { before_script: %w(ls pwd),
image: 'ruby:2.2',
services: ['postgres:9.1', 'mysql:5.5'],
variables: { VAR: 'value' },
after_script: ['make clean'],
- stages: ['build', 'pages'],
+ stages: %w(build pages),
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
spinach: { before_script: [], variables: {}, script: 'spinach' } }
@@ -84,7 +89,7 @@ describe Gitlab::Ci::Config::Entry::Global do
describe '#before_script_value' do
it 'returns correct script' do
- expect(global.before_script_value).to eq ['ls', 'pwd']
+ expect(global.before_script_value).to eq %w(ls pwd)
end
end
@@ -121,7 +126,7 @@ describe Gitlab::Ci::Config::Entry::Global do
context 'when deprecated types key defined' do
let(:hash) do
- { types: ['test', 'deploy'],
+ { types: %w(test deploy),
rspec: { script: 'rspec' } }
end
@@ -143,13 +148,14 @@ describe Gitlab::Ci::Config::Entry::Global do
expect(global.jobs_value).to eq(
rspec: { name: :rspec,
script: %w[rspec ls],
- before_script: ['ls', 'pwd'],
+ before_script: %w(ls pwd),
commands: "ls\npwd\nrspec\nls",
image: 'ruby:2.2',
services: ['postgres:9.1', 'mysql:5.5'],
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'] },
variables: { VAR: 'value' },
+ ignore: false,
after_script: ['make clean'] },
spinach: { name: :spinach,
before_script: [],
@@ -160,6 +166,7 @@ describe Gitlab::Ci::Config::Entry::Global do
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'] },
variables: {},
+ ignore: false,
after_script: ['make clean'] },
)
end
@@ -181,7 +188,7 @@ describe Gitlab::Ci::Config::Entry::Global do
it 'contains unspecified nodes' do
expect(global.descendants.first)
- .to be_an_instance_of Gitlab::Ci::Config::Entry::Unspecified
+ .not_to be_specified
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index fc9b8b86dc4..9249bb9c172 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -3,6 +3,20 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Job do
let(:entry) { described_class.new(config, name: :rspec) }
+ describe '.nodes' do
+ context 'when filtering all the entry/node names' do
+ subject { described_class.nodes.keys }
+
+ let(:result) do
+ %i[before_script script stage type after_script cache
+ image services only except variables artifacts
+ environment coverage]
+ end
+
+ it { is_expected.to match_array result }
+ end
+ end
+
describe 'validations' do
before { entry.compose! }
@@ -130,6 +144,7 @@ describe Gitlab::Ci::Config::Entry::Job do
script: %w[rspec],
commands: "ls\npwd\nrspec",
stage: 'test',
+ ignore: false,
after_script: %w[cleanup])
end
end
@@ -145,4 +160,82 @@ describe Gitlab::Ci::Config::Entry::Job do
end
end
end
+
+ describe '#manual_action?' do
+ context 'when job is a manual action' do
+ let(:config) { { script: 'deploy', when: 'manual' } }
+
+ it 'is a manual action' do
+ expect(entry).to be_manual_action
+ end
+ end
+
+ context 'when job is not a manual action' do
+ let(:config) { { script: 'deploy' } }
+
+ it 'is not a manual action' do
+ expect(entry).not_to be_manual_action
+ end
+ end
+ end
+
+ describe '#ignored?' do
+ context 'when job is a manual action' do
+ context 'when it is not specified if job is allowed to fail' do
+ let(:config) do
+ { script: 'deploy', when: 'manual' }
+ end
+
+ it 'is an ignored job' do
+ expect(entry).to be_ignored
+ end
+ end
+
+ context 'when job is allowed to fail' do
+ let(:config) do
+ { script: 'deploy', when: 'manual', allow_failure: true }
+ end
+
+ it 'is an ignored job' do
+ expect(entry).to be_ignored
+ end
+ end
+
+ context 'when job is not allowed to fail' do
+ let(:config) do
+ { script: 'deploy', when: 'manual', allow_failure: false }
+ end
+
+ it 'is not an ignored job' do
+ expect(entry).not_to be_ignored
+ end
+ end
+ end
+
+ context 'when job is not a manual action' do
+ context 'when it is not specified if job is allowed to fail' do
+ let(:config) { { script: 'deploy' } }
+
+ it 'is not an ignored job' do
+ expect(entry).not_to be_ignored
+ end
+ end
+
+ context 'when job is allowed to fail' do
+ let(:config) { { script: 'deploy', allow_failure: true } }
+
+ it 'is an ignored job' do
+ expect(entry).to be_ignored
+ end
+ end
+
+ context 'when job is not allowed to fail' do
+ let(:config) { { script: 'deploy', allow_failure: false } }
+
+ it 'is not an ignored job' do
+ expect(entry).not_to be_ignored
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index aaebf783962..7d104372ac6 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -62,10 +62,12 @@ describe Gitlab::Ci::Config::Entry::Jobs do
rspec: { name: :rspec,
script: %w[rspec],
commands: 'rspec',
+ ignore: false,
stage: 'test' },
spinach: { name: :spinach,
script: %w[spinach],
commands: 'spinach',
+ ignore: false,
stage: 'test' })
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/key_spec.rb b/spec/lib/gitlab/ci/config/entry/key_spec.rb
index a55e5b4b8ac..5d4de60bc8a 100644
--- a/spec/lib/gitlab/ci/config/entry/key_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/key_spec.rb
@@ -21,7 +21,7 @@ describe Gitlab::Ci::Config::Entry::Key do
end
context 'when entry value is not correct' do
- let(:config) { [ 'incorrect' ] }
+ let(:config) { ['incorrect'] }
describe '#errors' do
it 'saves errors' do
@@ -31,4 +31,10 @@ describe Gitlab::Ci::Config::Entry::Key do
end
end
end
+
+ describe '.default' do
+ it 'returns default key' do
+ expect(described_class.default).to eq 'default'
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/entry/paths_spec.rb b/spec/lib/gitlab/ci/config/entry/paths_spec.rb
index e60c9aaf661..1d9c5ddee9b 100644
--- a/spec/lib/gitlab/ci/config/entry/paths_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/paths_spec.rb
@@ -21,7 +21,7 @@ describe Gitlab::Ci::Config::Entry::Paths do
end
context 'when entry value is not valid' do
- let(:config) { [ 1 ] }
+ let(:config) { [1] }
describe '#errors' do
it 'saves errors' do
diff --git a/spec/lib/gitlab/ci/config/entry/script_spec.rb b/spec/lib/gitlab/ci/config/entry/script_spec.rb
index aa99cee2690..069eaa26422 100644
--- a/spec/lib/gitlab/ci/config/entry/script_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/script_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::Ci::Config::Entry::Script do
describe 'validations' do
context 'when entry config value is correct' do
- let(:config) { ['ls', 'pwd'] }
+ let(:config) { %w(ls pwd) }
describe '#value' do
it 'returns array of strings' do
diff --git a/spec/lib/gitlab/ci/config/entry/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
index 58327d08904..f15f02f403e 100644
--- a/spec/lib/gitlab/ci/config/entry/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
@@ -29,7 +29,7 @@ describe Gitlab::Ci::Config::Entry::Variables do
end
context 'when entry value is not correct' do
- let(:config) { [ :VAR, 'test' ] }
+ let(:config) { [:VAR, 'test'] }
describe '#errors' do
it 'saves errors' do
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
index b3c07347de1..8ad9b7cdf07 100644
--- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -62,7 +62,7 @@ describe Gitlab::Ci::Status::Build::Cancelable do
end
describe '#action_icon' do
- it { expect(subject.action_icon).to eq 'ban' }
+ it { expect(subject.action_icon).to eq 'icon_action_cancel' }
end
describe '#action_title' do
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index dccb29b5ef6..e648a3ac3a2 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -3,15 +3,23 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Build::Factory do
let(:user) { create(:user) }
let(:project) { build.project }
-
- subject { described_class.new(build, user) }
- let(:status) { subject.fabricate! }
+ let(:status) { factory.fabricate! }
+ let(:factory) { described_class.new(build, user) }
before { project.team << [user, :developer] }
context 'when build is successful' do
let(:build) { create(:ci_build, :success) }
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Retryable]
+ end
+
it 'fabricates a retryable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
end
@@ -19,6 +27,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'fabricates status with correct details' do
expect(status.text).to eq 'passed'
expect(status.icon).to eq 'icon_status_success'
+ expect(status.favicon).to eq 'favicon_status_success'
expect(status.label).to eq 'passed'
expect(status).to have_details
expect(status).to have_action
@@ -26,24 +35,74 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when build is failed' do
- let(:build) { create(:ci_build, :failed) }
+ context 'when build is not allowed to fail' do
+ let(:build) { create(:ci_build, :failed) }
- it 'fabricates a retryable build status' do
- expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Failed
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Retryable]
+ end
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'failed'
+ expect(status.icon).to eq 'icon_status_failed'
+ expect(status.favicon).to eq 'favicon_status_failed'
+ expect(status.label).to eq 'failed'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
end
- it 'fabricates status with correct details' do
- expect(status.text).to eq 'failed'
- expect(status.icon).to eq 'icon_status_failed'
- expect(status.label).to eq 'failed'
- expect(status).to have_details
- expect(status).to have_action
+ context 'when build is allowed to fail' do
+ let(:build) { create(:ci_build, :failed, :allowed_to_fail) }
+
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Failed
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Retryable,
+ Gitlab::Ci::Status::Build::FailedAllowed]
+ end
+
+ it 'fabricates a failed but allowed build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::FailedAllowed
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'failed'
+ expect(status.icon).to eq 'icon_status_warning'
+ expect(status.favicon).to eq 'favicon_status_failed'
+ expect(status.label).to eq 'failed (allowed to fail)'
+ expect(status).to have_details
+ expect(status).to have_action
+ expect(status.action_title).to include 'Retry'
+ expect(status.action_path).to include 'retry'
+ end
end
end
context 'when build is a canceled' do
let(:build) { create(:ci_build, :canceled) }
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Canceled
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Retryable]
+ end
+
it 'fabricates a retryable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
end
@@ -51,6 +110,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'fabricates status with correct details' do
expect(status.text).to eq 'canceled'
expect(status.icon).to eq 'icon_status_canceled'
+ expect(status.favicon).to eq 'favicon_status_canceled'
expect(status.label).to eq 'canceled'
expect(status).to have_details
expect(status).to have_action
@@ -60,6 +120,15 @@ describe Gitlab::Ci::Status::Build::Factory do
context 'when build is running' do
let(:build) { create(:ci_build, :running) }
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Running
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Cancelable]
+ end
+
it 'fabricates a canceable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
end
@@ -67,6 +136,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'fabricates status with correct details' do
expect(status.text).to eq 'running'
expect(status.icon).to eq 'icon_status_running'
+ expect(status.favicon).to eq 'favicon_status_running'
expect(status.label).to eq 'running'
expect(status).to have_details
expect(status).to have_action
@@ -76,6 +146,15 @@ describe Gitlab::Ci::Status::Build::Factory do
context 'when build is pending' do
let(:build) { create(:ci_build, :pending) }
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Pending
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Cancelable]
+ end
+
it 'fabricates a cancelable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
end
@@ -83,6 +162,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'fabricates status with correct details' do
expect(status.text).to eq 'pending'
expect(status.icon).to eq 'icon_status_pending'
+ expect(status.favicon).to eq 'favicon_status_pending'
expect(status.label).to eq 'pending'
expect(status).to have_details
expect(status).to have_action
@@ -92,6 +172,14 @@ describe Gitlab::Ci::Status::Build::Factory do
context 'when build is skipped' do
let(:build) { create(:ci_build, :skipped) }
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Skipped
+ end
+
+ it 'does not match extended statuses' do
+ expect(factory.extended_statuses).to be_empty
+ end
+
it 'fabricates a core skipped status' do
expect(status).to be_a Gitlab::Ci::Status::Skipped
end
@@ -99,6 +187,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'fabricates status with correct details' do
expect(status.text).to eq 'skipped'
expect(status.icon).to eq 'icon_status_skipped'
+ expect(status.favicon).to eq 'favicon_status_skipped'
expect(status.label).to eq 'skipped'
expect(status).to have_details
expect(status).not_to have_action
@@ -109,29 +198,52 @@ describe Gitlab::Ci::Status::Build::Factory do
context 'when build is a play action' do
let(:build) { create(:ci_build, :playable) }
- it 'fabricates a core skipped status' do
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Manual
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Play]
+ end
+
+ it 'fabricates a play detailed status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Play
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'manual'
+ expect(status.group).to eq 'manual'
expect(status.icon).to eq 'icon_status_manual'
+ expect(status.favicon).to eq 'favicon_status_manual'
expect(status.label).to eq 'manual play action'
expect(status).to have_details
expect(status).to have_action
+ expect(status.action_path).to include 'play'
end
end
context 'when build is an environment stop action' do
let(:build) { create(:ci_build, :playable, :teardown_environment) }
- it 'fabricates a core skipped status' do
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Manual
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Build::Stop]
+ end
+
+ it 'fabricates a stop detailed status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Stop
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'manual'
+ expect(status.group).to eq 'manual'
expect(status.icon).to eq 'icon_status_manual'
+ expect(status.favicon).to eq 'favicon_status_manual'
expect(status.label).to eq 'manual stop action'
expect(status).to have_details
expect(status).to have_action
diff --git a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
new file mode 100644
index 00000000000..20f71459738
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
@@ -0,0 +1,110 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::FailedAllowed do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'returns a warning icon' do
+ expect(subject.icon).to eq 'icon_status_warning'
+ end
+ end
+
+ describe '#label' do
+ it 'returns information about failed but allowed to fail status' do
+ expect(subject.label).to eq 'failed (allowed to fail)'
+ end
+ end
+
+ describe '#group' do
+ it 'returns status failed with warnings status group' do
+ expect(subject.group).to eq 'failed_with_warnings'
+ end
+ end
+
+ describe 'action details' do
+ describe '#has_action?' do
+ it 'does not decorate action details' do
+ expect(status).to receive(:has_action?)
+
+ subject.has_action?
+ end
+ end
+
+ describe '#action_path' do
+ it 'does not decorate action path' do
+ expect(status).to receive(:action_path)
+
+ subject.action_path
+ end
+ end
+
+ describe '#action_icon' do
+ it 'does not decorate action icon' do
+ expect(status).to receive(:action_icon)
+
+ subject.action_icon
+ end
+ end
+
+ describe '#action_title' do
+ it 'does not decorate action title' do
+ expect(status).to receive(:action_title)
+
+ subject.action_title
+ end
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is failed' do
+ context 'when build is allowed to fail' do
+ let(:build) { create(:ci_build, :failed, :allowed_to_fail) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not allowed to fail' do
+ let(:build) { create(:ci_build, :failed) }
+
+ it 'is not a correct match' do
+ expect(subject).not_to be true
+ end
+ end
+ end
+
+ context 'when build did not fail' do
+ context 'when build is allowed to fail' do
+ let(:build) { create(:ci_build, :success, :allowed_to_fail) }
+
+ it 'is not a correct match' do
+ expect(subject).not_to be true
+ end
+ end
+
+ context 'when build is not allowed to fail' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'is not a correct match' do
+ expect(subject).not_to be true
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb
index f1b50a59ce6..6c97a4fe5ca 100644
--- a/spec/lib/gitlab/ci/status/build/play_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -6,22 +6,10 @@ describe Gitlab::Ci::Status::Build::Play do
subject { described_class.new(status) }
- describe '#text' do
- it { expect(subject.text).to eq 'manual' }
- end
-
describe '#label' do
it { expect(subject.label).to eq 'manual play action' }
end
- describe '#icon' do
- it { expect(subject.icon).to eq 'icon_status_manual' }
- end
-
- describe '#group' do
- it { expect(subject.group).to eq 'manual' }
- end
-
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
@@ -44,7 +32,7 @@ describe Gitlab::Ci::Status::Build::Play do
end
describe '#action_icon' do
- it { expect(subject.action_icon).to eq 'play' }
+ it { expect(subject.action_icon).to eq 'icon_action_play' }
end
describe '#action_title' do
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
index 62036f8ec5d..2db0f8d29bd 100644
--- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -62,7 +62,7 @@ describe Gitlab::Ci::Status::Build::Retryable do
end
describe '#action_icon' do
- it { expect(subject.action_icon).to eq 'refresh' }
+ it { expect(subject.action_icon).to eq 'icon_action_retry' }
end
describe '#action_title' do
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
index 597e02e86e4..8d021c35a69 100644
--- a/spec/lib/gitlab/ci/status/build/stop_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -8,22 +8,10 @@ describe Gitlab::Ci::Status::Build::Stop do
described_class.new(status)
end
- describe '#text' do
- it { expect(subject.text).to eq 'manual' }
- end
-
describe '#label' do
it { expect(subject.label).to eq 'manual stop action' }
end
- describe '#icon' do
- it { expect(subject.icon).to eq 'icon_status_manual' }
- end
-
- describe '#group' do
- it { expect(subject.group).to eq 'manual' }
- end
-
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
@@ -46,7 +34,7 @@ describe Gitlab::Ci::Status::Build::Stop do
end
describe '#action_icon' do
- it { expect(subject.action_icon).to eq 'stop' }
+ it { expect(subject.action_icon).to eq 'icon_action_stop' }
end
describe '#action_title' do
diff --git a/spec/lib/gitlab/ci/status/canceled_spec.rb b/spec/lib/gitlab/ci/status/canceled_spec.rb
index 38412fe2e4f..530639a5897 100644
--- a/spec/lib/gitlab/ci/status/canceled_spec.rb
+++ b/spec/lib/gitlab/ci/status/canceled_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Canceled do
end
describe '#text' do
- it { expect(subject.label).to eq 'canceled' }
+ it { expect(subject.text).to eq 'canceled' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Canceled do
it { expect(subject.icon).to eq 'icon_status_canceled' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_canceled' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'canceled' }
end
diff --git a/spec/lib/gitlab/ci/status/created_spec.rb b/spec/lib/gitlab/ci/status/created_spec.rb
index 6d847484693..aef982e17f1 100644
--- a/spec/lib/gitlab/ci/status/created_spec.rb
+++ b/spec/lib/gitlab/ci/status/created_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Created do
end
describe '#text' do
- it { expect(subject.label).to eq 'created' }
+ it { expect(subject.text).to eq 'created' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Created do
it { expect(subject.icon).to eq 'icon_status_created' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_created' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'created' }
end
diff --git a/spec/lib/gitlab/ci/status/factory_spec.rb b/spec/lib/gitlab/ci/status/factory_spec.rb
index f92a1c149bf..bbf9c7c83a3 100644
--- a/spec/lib/gitlab/ci/status/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/factory_spec.rb
@@ -1,24 +1,135 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Factory do
- subject do
- described_class.new(resource, user)
+ let(:user) { create(:user) }
+ let(:fabricated_status) { factory.fabricate! }
+ let(:factory) { described_class.new(resource, user) }
+
+ context 'when object has a core status' do
+ HasStatus::AVAILABLE_STATUSES.each do |simple_status|
+ context "when simple core status is #{simple_status}" do
+ let(:resource) { double('resource', status: simple_status) }
+
+ let(:expected_status) do
+ Gitlab::Ci::Status.const_get(simple_status.capitalize)
+ end
+
+ it "fabricates a core status #{simple_status}" do
+ expect(fabricated_status).to be_a expected_status
+ end
+
+ it "matches a valid core status for #{simple_status}" do
+ expect(factory.core_status).to be_a expected_status
+ end
+
+ it "does not match any extended statuses for #{simple_status}" do
+ expect(factory.extended_statuses).to be_empty
+ end
+ end
+ end
end
- let(:user) { create(:user) }
+ context 'when resource supports multiple extended statuses' do
+ let(:resource) { double('resource', status: :success) }
- let(:status) { subject.fabricate! }
+ let(:first_extended_status) do
+ Class.new(SimpleDelegator) do
+ def first_method
+ 'first return value'
+ end
- context 'when object has a core status' do
- HasStatus::AVAILABLE_STATUSES.each do |core_status|
- context "when core status is #{core_status}" do
- let(:resource) { double(status: core_status) }
+ def second_method
+ 'second return value'
+ end
+
+ def self.matches?(*)
+ true
+ end
+ end
+ end
- it "fabricates a core status #{core_status}" do
- expect(status).to be_a(
- Gitlab::Ci::Status.const_get(core_status.capitalize))
+ let(:second_extended_status) do
+ Class.new(SimpleDelegator) do
+ def first_method
+ 'decorated return value'
end
+
+ def third_method
+ 'third return value'
+ end
+
+ def self.matches?(*)
+ true
+ end
+ end
+ end
+
+ shared_examples 'compound decorator factory' do
+ it 'fabricates compound decorator' do
+ expect(fabricated_status.first_method).to eq 'decorated return value'
+ expect(fabricated_status.second_method).to eq 'second return value'
+ expect(fabricated_status.third_method).to eq 'third return value'
end
+
+ it 'delegates to core status' do
+ expect(fabricated_status.text).to eq 'passed'
+ end
+
+ it 'latest matches status becomes a status name' do
+ expect(fabricated_status.class).to eq second_extended_status
+ end
+
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [first_extended_status, second_extended_status]
+ end
+ end
+
+ context 'when exclusive statuses are matches' do
+ before do
+ allow(described_class).to receive(:extended_statuses)
+ .and_return([[first_extended_status, second_extended_status]])
+ end
+
+ it 'does not fabricate compound decorator' do
+ expect(fabricated_status.first_method).to eq 'first return value'
+ expect(fabricated_status.second_method).to eq 'second return value'
+ expect(fabricated_status).not_to respond_to(:third_method)
+ end
+
+ it 'delegates to core status' do
+ expect(fabricated_status.text).to eq 'passed'
+ end
+
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses).to eq [first_extended_status]
+ end
+ end
+
+ context 'when exclusive statuses are not matched' do
+ before do
+ allow(described_class).to receive(:extended_statuses)
+ .and_return([[first_extended_status], [second_extended_status]])
+ end
+
+ it_behaves_like 'compound decorator factory'
+ end
+
+ context 'when using simplified status grouping' do
+ before do
+ allow(described_class).to receive(:extended_statuses)
+ .and_return([first_extended_status, second_extended_status])
+ end
+
+ it_behaves_like 'compound decorator factory'
end
end
end
diff --git a/spec/lib/gitlab/ci/status/failed_spec.rb b/spec/lib/gitlab/ci/status/failed_spec.rb
index 990d686d22c..9a25743885c 100644
--- a/spec/lib/gitlab/ci/status/failed_spec.rb
+++ b/spec/lib/gitlab/ci/status/failed_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Failed do
end
describe '#text' do
- it { expect(subject.label).to eq 'failed' }
+ it { expect(subject.text).to eq 'failed' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Failed do
it { expect(subject.icon).to eq 'icon_status_failed' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_failed' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'failed' }
end
diff --git a/spec/lib/gitlab/ci/status/manual_spec.rb b/spec/lib/gitlab/ci/status/manual_spec.rb
new file mode 100644
index 00000000000..6fdc3801d71
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/manual_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Manual do
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
+
+ describe '#text' do
+ it { expect(subject.text).to eq 'manual' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'manual action' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_manual' }
+ end
+
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_manual' }
+ end
+
+ describe '#group' do
+ it { expect(subject.group).to eq 'manual' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/pending_spec.rb b/spec/lib/gitlab/ci/status/pending_spec.rb
index 7bb6579c317..ffc53f0506b 100644
--- a/spec/lib/gitlab/ci/status/pending_spec.rb
+++ b/spec/lib/gitlab/ci/status/pending_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Pending do
end
describe '#text' do
- it { expect(subject.label).to eq 'pending' }
+ it { expect(subject.text).to eq 'pending' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Pending do
it { expect(subject.icon).to eq 'icon_status_pending' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_pending' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'pending' }
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb
new file mode 100644
index 00000000000..1a2b952d374
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/pipeline/blocked_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Pipeline::Blocked do
+ let(:pipeline) { double('pipeline') }
+
+ subject do
+ described_class.new(pipeline)
+ end
+
+ describe '#text' do
+ it 'overrides status text' do
+ expect(subject.text).to eq 'blocked'
+ end
+ end
+
+ describe '#label' do
+ it 'overrides status label' do
+ expect(subject.label).to eq 'waiting for manual action'
+ end
+ end
+
+ describe '.matches?' do
+ let(:user) { double('user') }
+ subject { described_class.matches?(pipeline, user) }
+
+ context 'when pipeline is blocked' do
+ let(:pipeline) { create(:ci_pipeline, :blocked) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when pipeline is not blocked' do
+ let(:pipeline) { create(:ci_pipeline, :success) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
index d4a2dc7fcc1..dd754b849b2 100644
--- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
@@ -3,29 +3,33 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Factory do
let(:user) { create(:user) }
let(:project) { pipeline.project }
-
- subject do
- described_class.new(pipeline, user)
- end
-
- let(:status) do
- subject.fabricate!
- end
+ let(:status) { factory.fabricate! }
+ let(:factory) { described_class.new(pipeline, user) }
before do
project.team << [user, :developer]
end
context 'when pipeline has a core status' do
- HasStatus::AVAILABLE_STATUSES.each do |core_status|
- context "when core status is #{core_status}" do
- let(:pipeline) do
- create(:ci_pipeline, status: core_status)
+ (HasStatus::AVAILABLE_STATUSES - [HasStatus::BLOCKED_STATUS])
+ .each do |simple_status|
+ context "when core status is #{simple_status}" do
+ let(:pipeline) { create(:ci_pipeline, status: simple_status) }
+
+ let(:expected_status) do
+ Gitlab::Ci::Status.const_get(simple_status.capitalize)
end
- it "fabricates a core status #{core_status}" do
- expect(status).to be_a(
- Gitlab::Ci::Status.const_get(core_status.capitalize))
+ it "matches correct core status for #{simple_status}" do
+ expect(factory.core_status).to be_a expected_status
+ end
+
+ it 'does not match extended statuses' do
+ expect(factory.extended_statuses).to be_empty
+ end
+
+ it "fabricates a core status #{simple_status}" do
+ expect(status).to be_a expected_status
end
it 'extends core status with common pipeline methods' do
@@ -36,6 +40,27 @@ describe Gitlab::Ci::Status::Pipeline::Factory do
end
end
end
+
+ context "when core status is manual" do
+ let(:pipeline) { create(:ci_pipeline, status: :manual) }
+
+ it "matches manual core status" do
+ expect(factory.core_status)
+ .to be_a Gitlab::Ci::Status::Manual
+ end
+
+ it 'matches a correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Pipeline::Blocked]
+ end
+
+ it 'extends core status with common pipeline methods' do
+ expect(status).to have_details
+ expect(status).not_to have_action
+ expect(status.details_path)
+ .to include "pipelines/#{pipeline.id}"
+ end
+ end
end
context 'when pipeline has warnings' do
@@ -47,13 +72,22 @@ describe Gitlab::Ci::Status::Pipeline::Factory do
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline)
end
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::SuccessWarning]
+ end
+
it 'fabricates extended "success with warnings" status' do
- expect(status)
- .to be_a Gitlab::Ci::Status::Pipeline::SuccessWithWarnings
+ expect(status).to be_a Gitlab::Ci::Status::SuccessWarning
end
- it 'extends core status with common pipeline methods' do
+ it 'extends core status with common pipeline method' do
expect(status).to have_details
+ expect(status.details_path).to include "pipelines/#{pipeline.id}"
end
end
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
deleted file mode 100644
index 979160eb9c4..00000000000
--- a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
- subject do
- described_class.new(double('status'))
- end
-
- describe '#test' do
- it { expect(subject.text).to eq 'passed' }
- end
-
- describe '#label' do
- it { expect(subject.label).to eq 'passed with warnings' }
- end
-
- describe '#icon' do
- it { expect(subject.icon).to eq 'icon_status_warning' }
- end
-
- describe '#group' do
- it { expect(subject.group).to eq 'success_with_warnings' }
- end
-
- describe '.matches?' do
- context 'when pipeline is successful' do
- let(:pipeline) do
- create(:ci_pipeline, status: :success)
- end
-
- context 'when pipeline has warnings' do
- before do
- allow(pipeline).to receive(:has_warnings?).and_return(true)
- end
-
- it 'is a correct match' do
- expect(described_class.matches?(pipeline, double)).to eq true
- end
- end
-
- context 'when pipeline does not have warnings' do
- it 'does not match' do
- expect(described_class.matches?(pipeline, double)).to eq false
- end
- end
- end
-
- context 'when pipeline is not successful' do
- let(:pipeline) do
- create(:ci_pipeline, status: :skipped)
- end
-
- context 'when pipeline has warnings' do
- before do
- allow(pipeline).to receive(:has_warnings?).and_return(true)
- end
-
- it 'does not match' do
- expect(described_class.matches?(pipeline, double)).to eq false
- end
- end
-
- context 'when pipeline does not have warnings' do
- it 'does not match' do
- expect(described_class.matches?(pipeline, double)).to eq false
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/ci/status/running_spec.rb b/spec/lib/gitlab/ci/status/running_spec.rb
index 852d6c06baf..0babf1fb54e 100644
--- a/spec/lib/gitlab/ci/status/running_spec.rb
+++ b/spec/lib/gitlab/ci/status/running_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Running do
end
describe '#text' do
- it { expect(subject.label).to eq 'running' }
+ it { expect(subject.text).to eq 'running' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Running do
it { expect(subject.icon).to eq 'icon_status_running' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_running' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'running' }
end
diff --git a/spec/lib/gitlab/ci/status/skipped_spec.rb b/spec/lib/gitlab/ci/status/skipped_spec.rb
index e00b356a24b..670747c9f0b 100644
--- a/spec/lib/gitlab/ci/status/skipped_spec.rb
+++ b/spec/lib/gitlab/ci/status/skipped_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Skipped do
end
describe '#text' do
- it { expect(subject.label).to eq 'skipped' }
+ it { expect(subject.text).to eq 'skipped' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Skipped do
it { expect(subject.icon).to eq 'icon_status_skipped' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_skipped' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'skipped' }
end
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index 6f8721d30c2..bbb40e2c1ab 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -43,4 +43,25 @@ describe Gitlab::Ci::Status::Stage::Factory do
end
end
end
+
+ context 'when stage has warnings' do
+ let(:stage) do
+ build(:ci_stage, name: 'test', status: :success, pipeline: pipeline)
+ end
+
+ before do
+ create(:ci_build, :allowed_to_fail, :failed,
+ stage: 'test', pipeline: stage.pipeline)
+ end
+
+ it 'fabricates extended "success with warnings" status' do
+ expect(status)
+ .to be_a Gitlab::Ci::Status::SuccessWarning
+ end
+
+ it 'extends core status with common stage method' do
+ expect(status).to have_details
+ expect(status.details_path).to include "pipelines/#{pipeline.id}##{stage.name}"
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/status/success_spec.rb b/spec/lib/gitlab/ci/status/success_spec.rb
index 4a89e1faf40..ff65b074808 100644
--- a/spec/lib/gitlab/ci/status/success_spec.rb
+++ b/spec/lib/gitlab/ci/status/success_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::Ci::Status::Success do
end
describe '#text' do
- it { expect(subject.label).to eq 'passed' }
+ it { expect(subject.text).to eq 'passed' }
end
describe '#label' do
@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Success do
it { expect(subject.icon).to eq 'icon_status_success' }
end
+ describe '#favicon' do
+ it { expect(subject.favicon).to eq 'favicon_status_success' }
+ end
+
describe '#group' do
it { expect(subject.group).to eq 'success' }
end
diff --git a/spec/lib/gitlab/ci/status/success_warning_spec.rb b/spec/lib/gitlab/ci/status/success_warning_spec.rb
new file mode 100644
index 00000000000..7e2269397c6
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/success_warning_spec.rb
@@ -0,0 +1,75 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::SuccessWarning do
+ subject do
+ described_class.new(double('status'))
+ end
+
+ describe '#test' do
+ it { expect(subject.text).to eq 'passed' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'passed with warnings' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_warning' }
+ end
+
+ describe '#group' do
+ it { expect(subject.group).to eq 'success_with_warnings' }
+ end
+
+ describe '.matches?' do
+ let(:matchable) { double('matchable') }
+
+ context 'when matchable subject is successful' do
+ before do
+ allow(matchable).to receive(:success?).and_return(true)
+ end
+
+ context 'when matchable subject has warnings' do
+ before do
+ allow(matchable).to receive(:has_warnings?).and_return(true)
+ end
+
+ it 'is a correct match' do
+ expect(described_class.matches?(matchable, double)).to eq true
+ end
+ end
+
+ context 'when matchable subject does not have warnings' do
+ before do
+ allow(matchable).to receive(:has_warnings?).and_return(false)
+ end
+
+ it 'does not match' do
+ expect(described_class.matches?(matchable, double)).to eq false
+ end
+ end
+ end
+
+ context 'when matchable subject is not successful' do
+ before do
+ allow(matchable).to receive(:success?).and_return(false)
+ end
+
+ context 'when matchable subject has warnings' do
+ before do
+ allow(matchable).to receive(:has_warnings?).and_return(true)
+ end
+
+ it 'does not match' do
+ expect(described_class.matches?(matchable, double)).to eq false
+ end
+ end
+
+ context 'when matchable subject does not have warnings' do
+ it 'does not match' do
+ expect(described_class.matches?(matchable, double)).to eq false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/trace_reader_spec.rb b/spec/lib/gitlab/ci/trace_reader_spec.rb
index f06d78694d6..ff5551bf703 100644
--- a/spec/lib/gitlab/ci/trace_reader_spec.rb
+++ b/spec/lib/gitlab/ci/trace_reader_spec.rb
@@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do
last_lines = random_lines
expected = lines.last(last_lines).join
+ result = subject.read(last_lines: last_lines)
- expect(subject.read(last_lines: last_lines)).to eq(expected)
+ expect(result).to eq(expected)
+ expect(result.encoding).to eq(Encoding.default_external)
end
end
it 'returns everything if trying to get too many lines' do
- expect(build_subject.read(last_lines: lines.size * 2)).to eq(lines.join)
+ result = build_subject.read(last_lines: lines.size * 2)
+
+ expect(result).to eq(lines.join)
+ expect(result.encoding).to eq(Encoding.default_external)
+ end
+
+ it 'returns all contents if last_lines is not specified' do
+ result = build_subject.read
+
+ expect(result).to eq(lines.join)
+ expect(result.encoding).to eq(Encoding.default_external)
end
it 'raises an error if not passing an integer for last_lines' do
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 1bbaca0739a..97af1c2523d 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
describe Gitlab::ClosingIssueExtractor, lib: true do
- let(:project) { create(:project) }
- let(:project2) { create(:project) }
+ let(:project) { create(:empty_project) }
+ let(:project2) { create(:empty_project) }
let(:forked_project) { Projects::ForkService.new(project, project.creator).execute }
- let(:issue) { create(:issue, project: project) }
- let(:issue2) { create(:issue, project: project2) }
+ let(:issue) { create(:issue, project: project) }
+ let(:issue2) { create(:issue, project: project2) }
let(:reference) { issue.to_reference }
let(:cross_reference) { issue2.to_reference(project) }
let(:fork_cross_reference) { issue.to_reference(forked_project) }
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 648d342ecf8..780ac0ad97e 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Conflict::File, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:rugged) { repository.rugged }
let(:their_commit) { rugged.branches['conflict-start'].target }
@@ -44,7 +44,7 @@ describe Gitlab::Conflict::File, lib: true do
it 'returns a file containing only the chosen parts of the resolved sections' do
expect(resolved_lines.chunk { |line| line.type || 'both' }.map(&:first)).
- to eq(['both', 'new', 'both', 'old', 'both', 'new', 'both'])
+ to eq(%w(both new both old both new both))
end
end
@@ -123,7 +123,7 @@ describe Gitlab::Conflict::File, lib: true do
it 'sets conflict to true for sections with only changed lines' do
conflict_file.sections.select { |section| section[:conflict] }.each do |section|
section[:lines].each do |line|
- expect(line.type).to be_in(['new', 'old'])
+ expect(line.type).to be_in(%w(new old))
end
end
end
@@ -251,7 +251,7 @@ FILE
describe '#as_json' do
it 'includes the blob path for the file' do
expect(conflict_file.as_json[:blob_path]).
- to eq("/#{project.namespace.to_param}/#{merge_request.project.to_param}/blob/#{our_commit.oid}/files/ruby/regex.rb")
+ to eq("/#{project.full_path}/blob/#{our_commit.oid}/files/ruby/regex.rb")
end
it 'includes the blob icon for the file' do
diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb
index 16eb3766356..2570f95dd21 100644
--- a/spec/lib/gitlab/conflict/parser_spec.rb
+++ b/spec/lib/gitlab/conflict/parser_spec.rb
@@ -120,43 +120,61 @@ CONFLICT
end
context 'when the file contents include conflict delimiters' do
- it 'raises UnexpectedDelimiter when there is a non-start delimiter first' do
- expect { parse_text('=======') }.
- to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
-
- expect { parse_text('>>>>>>> README.md') }.
- to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
-
- expect { parse_text('>>>>>>> some-other-path.md') }.
- not_to raise_error
+ context 'when there is a non-start delimiter first' do
+ it 'raises UnexpectedDelimiter when there is a middle delimiter first' do
+ expect { parse_text('=======') }.
+ to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ end
+
+ it 'raises UnexpectedDelimiter when there is an end delimiter first' do
+ expect { parse_text('>>>>>>> README.md') }.
+ to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ end
+
+ it 'does not raise when there is an end delimiter for a different path first' do
+ expect { parse_text('>>>>>>> some-other-path.md') }.
+ not_to raise_error
+ end
end
- it 'raises UnexpectedDelimiter when a start delimiter is followed by a non-middle delimiter' do
- start_text = "<<<<<<< README.md\n"
- end_text = "\n=======\n>>>>>>> README.md"
+ context 'when a start delimiter is followed by a non-middle delimiter' do
+ let(:start_text) { "<<<<<<< README.md\n" }
+ let(:end_text) { "\n=======\n>>>>>>> README.md" }
- expect { parse_text(start_text + '>>>>>>> README.md' + end_text) }.
- to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ it 'raises UnexpectedDelimiter when it is followed by an end delimiter' do
+ expect { parse_text(start_text + '>>>>>>> README.md' + end_text) }.
+ to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ end
- expect { parse_text(start_text + start_text + end_text) }.
- to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ it 'raises UnexpectedDelimiter when it is followed by another start delimiter' do
+ expect { parse_text(start_text + start_text + end_text) }.
+ to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ end
- expect { parse_text(start_text + '>>>>>>> some-other-path.md' + end_text) }.
- not_to raise_error
+ it 'does not raise when it is followed by a start delimiter for a different path' do
+ expect { parse_text(start_text + '>>>>>>> some-other-path.md' + end_text) }.
+ not_to raise_error
+ end
end
- it 'raises UnexpectedDelimiter when a middle delimiter is followed by a non-end delimiter' do
- start_text = "<<<<<<< README.md\n=======\n"
- end_text = "\n>>>>>>> README.md"
+ context 'when a middle delimiter is followed by a non-end delimiter' do
+ let(:start_text) { "<<<<<<< README.md\n=======\n" }
+ let(:end_text) { "\n>>>>>>> README.md" }
- expect { parse_text(start_text + '=======' + end_text) }.
- to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ it 'raises UnexpectedDelimiter when it is followed by another middle delimiter' do
+ expect { parse_text(start_text + '=======' + end_text) }.
+ to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ end
- expect { parse_text(start_text + start_text + end_text) }.
- to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ it 'raises UnexpectedDelimiter when it is followed by a start delimiter' do
+ expect { parse_text(start_text + start_text + end_text) }.
+ to raise_error(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ end
- expect { parse_text(start_text + '>>>>>>> some-other-path.md' + end_text) }.
- not_to raise_error
+ it 'does not raise when it is followed by a start delimiter for another path' do
+ expect { parse_text(start_text + '<<<<<<< some-other-path.md' + end_text) }.
+ not_to raise_error
+ end
end
it 'raises MissingEndDelimiter when there is no end delimiter at the end' do
@@ -184,9 +202,20 @@ CONFLICT
to raise_error(Gitlab::Conflict::Parser::UnmergeableFile)
end
- it 'raises UnsupportedEncoding when the file contains non-UTF-8 characters' do
- expect { parse_text("a\xC4\xFC".force_encoding(Encoding::ASCII_8BIT)) }.
- to raise_error(Gitlab::Conflict::Parser::UnsupportedEncoding)
+ # All text from Rugged has an encoding of ASCII_8BIT, so force that in
+ # these strings.
+ context 'when the file contains UTF-8 characters' do
+ it 'does not raise' do
+ expect { parse_text("Espa\xC3\xB1a".force_encoding(Encoding::ASCII_8BIT)) }.
+ not_to raise_error
+ end
+ end
+
+ context 'when the file contains non-UTF-8 characters' do
+ it 'raises UnsupportedEncoding' do
+ expect { parse_text("a\xC4\xFC".force_encoding(Encoding::ASCII_8BIT)) }.
+ to raise_error(Gitlab::Conflict::Parser::UnsupportedEncoding)
+ end
end
end
end
diff --git a/spec/lib/gitlab/contributions_calendar_spec.rb b/spec/lib/gitlab/contributions_calendar_spec.rb
index 01b2a55b63c..e18a219ef36 100644
--- a/spec/lib/gitlab/contributions_calendar_spec.rb
+++ b/spec/lib/gitlab/contributions_calendar_spec.rb
@@ -17,7 +17,7 @@ describe Gitlab::ContributionsCalendar do
end
let(:feature_project) do
- create(:empty_project, :public, issues_access_level: ProjectFeature::PRIVATE) do |project|
+ create(:empty_project, :public, :issues_private) do |project|
create(:project_member, user: contributor, project: project).project
end
end
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index 004341ffd02..b01c4805a34 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -1,36 +1,64 @@
require 'spec_helper'
describe Gitlab::CurrentSettings do
+ include StubENV
+
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ end
+
describe '#current_application_settings' do
- it 'attempts to use cached values first' do
- allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true)
- expect(ApplicationSetting).to receive(:current).and_return(::ApplicationSetting.create_from_defaults)
- expect(ApplicationSetting).not_to receive(:last)
+ context 'with DB available' do
+ before do
+ allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true)
+ end
- expect(current_application_settings).to be_a(ApplicationSetting)
- end
+ it 'attempts to use cached values first' do
+ expect(ApplicationSetting).to receive(:current)
+ expect(ApplicationSetting).not_to receive(:last)
+
+ expect(current_application_settings).to be_a(ApplicationSetting)
+ end
- it 'does not attempt to connect to DB or Redis' do
- allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(false)
- expect(ApplicationSetting).not_to receive(:current)
- expect(ApplicationSetting).not_to receive(:last)
+ it 'falls back to DB if Redis returns an empty value' do
+ expect(ApplicationSetting).to receive(:last).and_call_original
- expect(current_application_settings).to eq fake_application_settings
+ expect(current_application_settings).to be_a(ApplicationSetting)
+ end
+
+ it 'falls back to DB if Redis fails' do
+ expect(ApplicationSetting).to receive(:current).and_raise(::Redis::BaseError)
+ expect(ApplicationSetting).to receive(:last).and_call_original
+
+ expect(current_application_settings).to be_a(ApplicationSetting)
+ end
end
- it 'falls back to DB if Redis returns an empty value' do
- allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true)
- expect(ApplicationSetting).to receive(:last).and_call_original
+ context 'with DB unavailable' do
+ before do
+ allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(false)
+ end
- expect(current_application_settings).to be_a(ApplicationSetting)
+ it 'returns an in-memory ApplicationSetting object' do
+ expect(ApplicationSetting).not_to receive(:current)
+ expect(ApplicationSetting).not_to receive(:last)
+
+ expect(current_application_settings).to be_a(OpenStruct)
+ end
end
- it 'falls back to DB if Redis fails' do
- allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true)
- expect(ApplicationSetting).to receive(:current).and_raise(::Redis::BaseError)
- expect(ApplicationSetting).to receive(:last).and_call_original
+ context 'when ENV["IN_MEMORY_APPLICATION_SETTINGS"] is true' do
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'true')
+ end
+
+ it 'returns an in-memory ApplicationSetting object' do
+ expect(ApplicationSetting).not_to receive(:current)
+ expect(ApplicationSetting).not_to receive(:last)
- expect(current_application_settings).to be_a(ApplicationSetting)
+ expect(current_application_settings).to be_a(ApplicationSetting)
+ expect(current_application_settings).not_to be_persisted
+ end
end
end
end
diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
new file mode 100644
index 00000000000..c455cd9b942
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+describe Gitlab::CycleAnalytics::BaseEventFetcher do
+ let(:max_events) { 2 }
+ let(:project) { create(:project) }
+ let(:user) { create(:user, :admin) }
+ let(:start_time_attrs) { Issue.arel_table[:created_at] }
+ let(:end_time_attrs) { [Issue::Metrics.arel_table[:first_associated_with_milestone_at]] }
+ let(:options) do
+ { start_time_attrs: start_time_attrs,
+ end_time_attrs: end_time_attrs,
+ from: 30.days.ago }
+ end
+
+ subject do
+ described_class.new(project: project,
+ stage: :issue,
+ options: options).fetch
+ end
+
+ before do
+ allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return(Issue.all)
+ allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:serialize) do |event|
+ event
+ end
+
+ stub_const('Gitlab::CycleAnalytics::BaseEventFetcher::MAX_EVENTS', max_events)
+
+ setup_events(count: 3)
+ end
+
+ it 'limits the rows to the max number' do
+ expect(subject.count).to eq(max_events)
+ end
+
+ def setup_events(count:)
+ count.times do
+ issue = create(:issue, project: project, created_at: 2.days.ago)
+ milestone = create(:milestone, project: project)
+
+ issue.update(milestone: milestone)
+ create_merge_request_closing_issue(issue)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
index fb6b6c4a8d2..3dd76ba5b8a 100644
--- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::CycleAnalytics::StageSummary, models: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:from) { 1.day.ago }
let(:user) { create(:user, :admin) }
subject { described_class.new(project, from: Time.now, current_user: user).data }
@@ -15,7 +15,7 @@ describe Gitlab::CycleAnalytics::StageSummary, models: true do
end
it "doesn't find issues from other projects" do
- Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project)) }
+ Timecop.freeze(5.days.from_now) { create(:issue, project: create(:empty_project)) }
expect(subject.first[:value]).to eq(0)
end
@@ -30,7 +30,7 @@ describe Gitlab::CycleAnalytics::StageSummary, models: true do
end
it "doesn't find commits from other projects" do
- Timecop.freeze(5.days.from_now) { create_commit("Test message", create(:project), user, 'master') }
+ Timecop.freeze(5.days.from_now) { create_commit("Test message", create(:project, :repository), user, 'master') }
expect(subject.second[:value]).to eq(0)
end
@@ -51,7 +51,9 @@ describe Gitlab::CycleAnalytics::StageSummary, models: true do
end
it "doesn't find commits from other projects" do
- Timecop.freeze(5.days.from_now) { create(:deployment, project: create(:project)) }
+ Timecop.freeze(5.days.from_now) do
+ create(:deployment, project: create(:project, :repository))
+ end
expect(subject.third[:value]).to eq(0)
end
diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb
index 6c71e98066b..91c43f2bdc0 100644
--- a/spec/lib/gitlab/data_builder/build_spec.rb
+++ b/spec/lib/gitlab/data_builder/build_spec.rb
@@ -17,5 +17,31 @@ describe Gitlab::DataBuilder::Build do
it { expect(data[:build_allow_failure]).to eq(false) }
it { expect(data[:project_id]).to eq(build.project.id) }
it { expect(data[:project_name]).to eq(build.project.name_with_namespace) }
+
+ context 'commit author_url' do
+ context 'when no commit present' do
+ let(:build) { create(:ci_build) }
+
+ it 'sets to mailing address of git_author_email' do
+ expect(data[:commit][:author_url]).to eq("mailto:#{build.pipeline.git_author_email}")
+ end
+ end
+
+ context 'when commit present but has no author' do
+ let(:build) { create(:ci_build, :with_commit) }
+
+ it 'sets to mailing address of git_author_email' do
+ expect(data[:commit][:author_url]).to eq("mailto:#{build.pipeline.git_author_email}")
+ end
+ end
+
+ context 'when commit and author are present' do
+ let(:build) { create(:ci_build, :with_commit_and_author) }
+
+ it 'sets to GitLab user url' do
+ expect(data[:commit][:author_url]).to eq(Gitlab::Routing.url_helpers.user_url(username: build.commit.author.username))
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb
index 9a4dec91e56..04ec34492e1 100644
--- a/spec/lib/gitlab/data_builder/note_spec.rb
+++ b/spec/lib/gitlab/data_builder/note_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::DataBuilder::Note, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:data) { described_class.build(note, user) }
let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors
diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb
index a68f5943a6a..f13041e498c 100644
--- a/spec/lib/gitlab/data_builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::DataBuilder::Pipeline do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb
index a379f798a16..dbcfb9b7400 100644
--- a/spec/lib/gitlab/data_builder/push_spec.rb
+++ b/spec/lib/gitlab/data_builder/push_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::DataBuilder::Push, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
describe '.build_sample' do
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 7fd25b9e5bf..e007044868c 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -12,15 +12,14 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
describe '#add_concurrent_index' do
context 'outside a transaction' do
before do
- expect(model).to receive(:transaction_open?).and_return(false)
-
- unless Gitlab::Database.postgresql?
- allow_any_instance_of(Gitlab::Database::MigrationHelpers).to receive(:disable_statement_timeout)
- end
+ allow(model).to receive(:transaction_open?).and_return(false)
end
context 'using PostgreSQL' do
- before { expect(Gitlab::Database).to receive(:postgresql?).and_return(true) }
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(true)
+ allow(model).to receive(:disable_statement_timeout)
+ end
it 'creates the index concurrently' do
expect(model).to receive(:add_index).
@@ -59,6 +58,81 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
end
end
+ describe '#add_concurrent_foreign_key' do
+ context 'inside a transaction' do
+ it 'raises an error' do
+ expect(model).to receive(:transaction_open?).and_return(true)
+
+ expect do
+ model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
+ end.to raise_error(RuntimeError)
+ end
+ end
+
+ context 'outside a transaction' do
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ context 'using MySQL' do
+ it 'creates a regular foreign key' do
+ allow(Gitlab::Database).to receive(:mysql?).and_return(true)
+
+ expect(model).to receive(:add_foreign_key).
+ with(:projects, :users, column: :user_id, on_delete: :cascade)
+
+ model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
+ end
+ end
+
+ context 'using PostgreSQL' do
+ before do
+ allow(Gitlab::Database).to receive(:mysql?).and_return(false)
+ end
+
+ it 'creates a concurrent foreign key' do
+ expect(model).to receive(:disable_statement_timeout)
+ expect(model).to receive(:execute).ordered.with(/NOT VALID/)
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+
+ model.add_concurrent_foreign_key(:projects, :users, column: :user_id)
+ end
+ end
+ end
+ end
+
+ describe '#concurrent_foreign_key_name' do
+ it 'returns the name for a foreign key' do
+ name = model.concurrent_foreign_key_name(:this_is_a_very_long_table_name,
+ :with_a_very_long_column_name)
+
+ expect(name).to be_an_instance_of(String)
+ expect(name.length).to eq(13)
+ end
+ end
+
+ describe '#disable_statement_timeout' do
+ context 'using PostgreSQL' do
+ it 'disables statement timeouts' do
+ expect(Gitlab::Database).to receive(:postgresql?).and_return(true)
+
+ expect(model).to receive(:execute).with('SET statement_timeout TO 0')
+
+ model.disable_statement_timeout
+ end
+ end
+
+ context 'using MySQL' do
+ it 'does nothing' do
+ expect(Gitlab::Database).to receive(:postgresql?).and_return(false)
+
+ expect(model).not_to receive(:execute)
+
+ model.disable_statement_timeout
+ end
+ end
+ end
+
describe '#update_column_in_batches' do
before do
create_list(:empty_project, 5)
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 3031559c613..4ce4e6e1034 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -1,10 +1,22 @@
require 'spec_helper'
-class MigrationTest
- include Gitlab::Database
-end
-
describe Gitlab::Database, lib: true do
+ before do
+ stub_const('MigrationTest', Class.new { include Gitlab::Database })
+ end
+
+ describe '.config' do
+ it 'returns a Hash' do
+ expect(described_class.config).to be_an_instance_of(Hash)
+ end
+ end
+
+ describe '.adapter_name' do
+ it 'returns the name of the adapter' do
+ expect(described_class.adapter_name).to be_an_instance_of(String)
+ end
+ end
+
# These are just simple smoke tests to check if the methods work (regardless
# of what they may return).
describe '.mysql?' do
@@ -55,6 +67,85 @@ describe Gitlab::Database, lib: true do
end
end
+ describe '.nulls_first_order' do
+ context 'when using PostgreSQL' do
+ before { expect(described_class).to receive(:postgresql?).and_return(true) }
+
+ it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC NULLS FIRST'}
+ it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column DESC NULLS FIRST'}
+ end
+
+ context 'when using MySQL' do
+ before { expect(described_class).to receive(:postgresql?).and_return(false) }
+
+ it { expect(described_class.nulls_first_order('column', 'ASC')).to eq 'column ASC'}
+ it { expect(described_class.nulls_first_order('column', 'DESC')).to eq 'column IS NULL, column DESC'}
+ end
+ end
+
+ describe '.with_connection_pool' do
+ it 'creates a new connection pool and disconnect it after used' do
+ closed_pool = nil
+
+ described_class.with_connection_pool(1) do |pool|
+ pool.with_connection do |connection|
+ connection.execute('SELECT 1 AS value')
+ end
+
+ expect(pool).to be_connected
+
+ closed_pool = pool
+ end
+
+ expect(closed_pool).not_to be_connected
+ end
+
+ it 'disconnects the pool even an exception was raised' do
+ error = Class.new(RuntimeError)
+ closed_pool = nil
+
+ begin
+ described_class.with_connection_pool(1) do |pool|
+ pool.with_connection do |connection|
+ connection.execute('SELECT 1 AS value')
+ end
+
+ closed_pool = pool
+
+ raise error.new('boom')
+ end
+ rescue error
+ end
+
+ expect(closed_pool).not_to be_connected
+ end
+ end
+
+ describe '.create_connection_pool' do
+ it 'creates a new connection pool with specific pool size' do
+ pool = described_class.create_connection_pool(5)
+
+ begin
+ expect(pool)
+ .to be_kind_of(ActiveRecord::ConnectionAdapters::ConnectionPool)
+
+ expect(pool.spec.config[:pool]).to eq(5)
+ ensure
+ pool.disconnect!
+ end
+ end
+
+ it 'allows setting of a custom hostname' do
+ pool = described_class.create_connection_pool(5, '127.0.0.1')
+
+ begin
+ expect(pool.spec.config[:host]).to eq('127.0.0.1')
+ ensure
+ pool.disconnect!
+ end
+ end
+ end
+
describe '#true_value' do
it 'returns correct value for PostgreSQL' do
expect(described_class).to receive(:postgresql?).and_return(true)
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index 38475792d93..050689b7c9a 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::File, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.raw_diffs.first }
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
index 1c2ddeed692..c6bd4e81f4f 100644
--- a/spec/lib/gitlab/diff/highlight_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::Highlight, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { project.commit(sample_commit.id) }
let(:diff) { commit.raw_diffs.first }
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: project.repository) }
@@ -12,29 +12,29 @@ describe Gitlab::Diff::Highlight, lib: true do
context "with a diff file" do
let(:subject) { Gitlab::Diff::Highlight.new(diff_file, repository: project.repository).highlight }
- it 'should return Gitlab::Diff::Line elements' do
+ it 'returns Gitlab::Diff::Line elements' do
expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line)
end
- it 'should not modify "match" lines' do
+ it 'does not modify "match" lines' do
expect(subject[0].text).to eq('@@ -6,12 +6,18 @@ module Popen')
expect(subject[22].text).to eq('@@ -19,6 +25,7 @@ module Popen')
end
it 'highlights and marks unchanged lines' do
- code = %Q{ <span id="LC7" class="line"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>\n}
+ code = %Q{ <span id="LC7" class="line" lang="ruby"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>\n}
expect(subject[2].text).to eq(code)
end
it 'highlights and marks removed lines' do
- code = %Q{-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n}
+ code = %Q{-<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n}
expect(subject[4].text).to eq(code)
end
it 'highlights and marks added lines' do
- code = %Q{+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
+ code = %Q{+<span id="LC9" class="line" lang="ruby"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
expect(subject[5].text).to eq(code)
end
@@ -43,31 +43,31 @@ describe Gitlab::Diff::Highlight, lib: true do
context "with diff lines" do
let(:subject) { Gitlab::Diff::Highlight.new(diff_file.diff_lines, repository: project.repository).highlight }
- it 'should return Gitlab::Diff::Line elements' do
+ it 'returns Gitlab::Diff::Line elements' do
expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line)
end
- it 'should not modify "match" lines' do
+ it 'does not modify "match" lines' do
expect(subject[0].text).to eq('@@ -6,12 +6,18 @@ module Popen')
expect(subject[22].text).to eq('@@ -19,6 +25,7 @@ module Popen')
end
it 'marks unchanged lines' do
- code = %Q{ def popen(cmd, path=nil)}
+ code = %q{ def popen(cmd, path=nil)}
expect(subject[2].text).to eq(code)
expect(subject[2].text).not_to be_html_safe
end
it 'marks removed lines' do
- code = %Q{- raise "System commands must be given as an array of strings"}
+ code = %q{- raise "System commands must be given as an array of strings"}
expect(subject[4].text).to eq(code)
expect(subject[4].text).not_to be_html_safe
end
it 'marks added lines' do
- code = %Q{+ raise <span class='idiff left right'>RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;}
+ code = %q{+ raise <span class='idiff left right'>RuntimeError, </span>&quot;System commands must be given as an array of strings&quot;}
expect(subject[5].text).to eq(code)
expect(subject[5].text).to be_html_safe
diff --git a/spec/lib/gitlab/diff/line_mapper_spec.rb b/spec/lib/gitlab/diff/line_mapper_spec.rb
index 4b943fa382d..2c7ecd1907e 100644
--- a/spec/lib/gitlab/diff/line_mapper_spec.rb
+++ b/spec/lib/gitlab/diff/line_mapper_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::LineMapper, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
let(:diffs) { commit.raw_diffs }
diff --git a/spec/lib/gitlab/diff/parallel_diff_spec.rb b/spec/lib/gitlab/diff/parallel_diff_spec.rb
index af18d3c25a6..0f779339c54 100644
--- a/spec/lib/gitlab/diff/parallel_diff_spec.rb
+++ b/spec/lib/gitlab/diff/parallel_diff_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::ParallelDiff, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
let(:diffs) { commit.raw_diffs }
@@ -12,7 +12,7 @@ describe Gitlab::Diff::ParallelDiff, lib: true do
subject { described_class.new(diff_file) }
describe '#parallelize' do
- it 'should return an array of arrays containing the parsed diff' do
+ it 'returns an array of arrays containing the parsed diff' do
diff_lines = diff_file.highlighted_diff_lines
expected = [
# Unchanged lines
diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb
index b983d73f8be..e76128ecd87 100644
--- a/spec/lib/gitlab/diff/parser_spec.rb
+++ b/spec/lib/gitlab/diff/parser_spec.rb
@@ -91,6 +91,54 @@ eos
end
end
+ describe '\ No newline at end of file' do
+ it "parses nonewline in one file correctly" do
+ first_nonewline_diff = <<~END
+ --- a/test
+ +++ b/test
+ @@ -1,2 +1,2 @@
+ +ipsum
+ lorem
+ -ipsum
+ \\ No newline at end of file
+ END
+ lines = parser.parse(first_nonewline_diff.lines).to_a
+
+ expect(lines[0].type).to eq('new')
+ expect(lines[0].text).to eq('+ipsum')
+ expect(lines[2].type).to eq('old')
+ expect(lines[3].type).to eq('old-nonewline')
+ expect(lines[1].old_pos).to eq(1)
+ expect(lines[1].new_pos).to eq(2)
+ end
+
+ it "parses nonewline in two files correctly" do
+ both_nonewline_diff = <<~END
+ --- a/test
+ +++ b/test
+ @@ -1,2 +1,2 @@
+ -lorem
+ -ipsum
+ \\ No newline at end of file
+ +ipsum
+ +lorem
+ \\ No newline at end of file
+ END
+ lines = parser.parse(both_nonewline_diff.lines).to_a
+
+ expect(lines[0].type).to eq('old')
+ expect(lines[1].type).to eq('old')
+ expect(lines[2].type).to eq('old-nonewline')
+ expect(lines[5].type).to eq('new-nonewline')
+ expect(lines[3].text).to eq('+ipsum')
+ expect(lines[3].old_pos).to eq(3)
+ expect(lines[3].new_pos).to eq(1)
+ expect(lines[4].text).to eq('+lorem')
+ expect(lines[4].old_pos).to eq(3)
+ expect(lines[4].new_pos).to eq(2)
+ end
+ end
+
context 'when lines is empty' do
it { expect(parser.parse([])).to eq([]) }
it { expect(parser.parse(nil)).to eq([]) }
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index 6e8fff6f516..cdf0af6d7ef 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Diff::Position, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
describe "position for an added file" do
let(:commit) { project.commit("2ea1f3dec713d940208fb5ce4a38765ecb5d3f73") }
diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb
index c268f84c759..994995b57b8 100644
--- a/spec/lib/gitlab/diff/position_tracer_spec.rb
+++ b/spec/lib/gitlab/diff/position_tracer_spec.rb
@@ -51,7 +51,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:current_user) { project.owner }
let(:repository) { project.repository }
let(:file_name) { "test-file" }
@@ -99,7 +99,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do
Files::CreateService.new(
project,
current_user,
- source_branch: branch_name,
+ start_branch: branch_name,
target_branch: branch_name,
commit_message: "Create file",
file_path: file_name,
@@ -112,7 +112,7 @@ describe Gitlab::Diff::PositionTracer, lib: true do
Files::UpdateService.new(
project,
current_user,
- source_branch: branch_name,
+ start_branch: branch_name,
target_branch: branch_name,
commit_message: "Update file",
file_path: file_name,
@@ -122,10 +122,10 @@ describe Gitlab::Diff::PositionTracer, lib: true do
end
def delete_file(branch_name, file_name)
- Files::DeleteService.new(
+ Files::DestroyService.new(
project,
current_user,
- source_branch: branch_name,
+ start_branch: branch_name,
target_branch: branch_name,
commit_message: "Delete file",
file_path: file_name
@@ -1640,7 +1640,9 @@ describe Gitlab::Diff::PositionTracer, lib: true do
}
merge_request = create(:merge_request, source_branch: second_create_file_commit.sha, target_branch: branch_name, source_project: project)
- repository.merge(current_user, merge_request, options)
+
+ repository.merge(current_user, merge_request.diff_head_sha, merge_request, options)
+
project.commit(branch_name)
end
diff --git a/spec/lib/gitlab/email/email_shared_blocks.rb b/spec/lib/gitlab/email/email_shared_blocks.rb
index 19298e261e3..9d806fc524d 100644
--- a/spec/lib/gitlab/email/email_shared_blocks.rb
+++ b/spec/lib/gitlab/email/email_shared_blocks.rb
@@ -18,7 +18,7 @@ shared_context :email_shared_context do
end
end
-shared_examples :email_shared_examples do
+shared_examples :reply_processing_shared_examples do
context "when the user could not be found" do
before do
user.destroy
diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
index cb3651e3845..4a9c9a7fe34 100644
--- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb
@@ -3,7 +3,7 @@ require_relative '../email_shared_blocks'
describe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
include_context :email_shared_context
- it_behaves_like :email_shared_examples
+ it_behaves_like :reply_processing_shared_examples
before do
stub_incoming_email_setting(enabled: true, address: "incoming+%{key}@appmail.adventuretime.ooo")
@@ -13,7 +13,7 @@ describe Gitlab::Email::Handler::CreateIssueHandler, lib: true do
let(:email_raw) { fixture_file('emails/valid_new_issue.eml') }
let(:namespace) { create(:namespace, path: 'gitlabhq') }
- let!(:project) { create(:project, :public, namespace: namespace) }
+ let!(:project) { create(:project, :public, :repository, namespace: namespace) }
let!(:user) do
create(
:user,
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index 48660d1dd1b..b300feaabe1 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -3,7 +3,7 @@ require_relative '../email_shared_blocks'
describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
include_context :email_shared_context
- it_behaves_like :email_shared_examples
+ it_behaves_like :reply_processing_shared_examples
before do
stub_incoming_email_setting(enabled: true, address: "reply+%{key}@appmail.adventuretime.ooo")
@@ -11,7 +11,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
end
let(:email_raw) { fixture_file('emails/valid_reply.eml') }
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
let(:note) { create(:diff_note_on_merge_request, project: project) }
let(:noteable) { note.noteable }
@@ -174,6 +174,12 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do
it_behaves_like 'an email that contains a mail key', 'References'
end
+
+ context 'mail key is in the References header with a comma' do
+ let(:email_raw) { fixture_file('emails/reply_without_subaddressing_and_key_inside_references_with_a_comma.eml') }
+
+ it_behaves_like 'an email that contains a mail key', 'References'
+ end
end
end
end
diff --git a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
new file mode 100644
index 00000000000..0939e6c4514
--- /dev/null
+++ b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+require_relative '../email_shared_blocks'
+
+describe Gitlab::Email::Handler::UnsubscribeHandler, lib: true do
+ include_context :email_shared_context
+
+ before do
+ stub_incoming_email_setting(enabled: true, address: 'reply+%{key}@appmail.adventuretime.ooo')
+ stub_config_setting(host: 'localhost')
+ end
+
+ let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}+unsubscribe") }
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+ let(:noteable) { create(:issue, project: project) }
+
+ let!(:sent_notification) { SentNotification.record(noteable, user.id, mail_key) }
+
+ context 'when notification concerns a commit' do
+ let(:commit) { create(:commit, project: project) }
+ let!(:sent_notification) { SentNotification.record(commit, user.id, mail_key) }
+
+ it 'handler does not raise an error' do
+ expect { receiver.execute }.not_to raise_error
+ end
+ end
+
+ context 'user is unsubscribed' do
+ it 'leaves user unsubscribed' do
+ expect { receiver.execute }.not_to change { noteable.subscribed?(user) }.from(false)
+ end
+ end
+
+ context 'user is subscribed' do
+ before do
+ noteable.subscribe(user)
+ end
+
+ it 'unsubscribes user from notable' do
+ expect { receiver.execute }.to change { noteable.subscribed?(user) }.from(true).to(false)
+ end
+ end
+
+ context 'when the noteable could not be found' do
+ before do
+ noteable.destroy
+ end
+
+ it 'raises a NoteableNotFoundError' do
+ expect { receiver.execute }.to raise_error(Gitlab::Email::NoteableNotFoundError)
+ end
+ end
+
+ context 'when no sent notification for the mail key could be found' do
+ let(:email_raw) { fixture_file('emails/wrong_mail_key.eml') }
+
+ it 'raises a SentNotificationNotFoundError' do
+ expect { receiver.execute }.to raise_error(Gitlab::Email::SentNotificationNotFoundError)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb
index 5b966bddb6a..7b3291b8315 100644
--- a/spec/lib/gitlab/email/message/repository_push_spec.rb
+++ b/spec/lib/gitlab/email/message/repository_push_spec.rb
@@ -4,7 +4,7 @@ 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!(:project) { create(:project, :repository, name: 'my_project', namespace: group) }
let!(:author) { create(:author, name: 'Author') }
let(:message) do
diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb
new file mode 100644
index 00000000000..6ec4360adc2
--- /dev/null
+++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb
@@ -0,0 +1,176 @@
+require 'spec_helper'
+
+describe Gitlab::EtagCaching::Middleware do
+ let(:app) { double(:app) }
+ let(:middleware) { described_class.new(app) }
+ let(:app_status_code) { 200 }
+ let(:if_none_match) { nil }
+ let(:enabled_path) { '/gitlab-org/gitlab-ce/noteable/issue/1/notes' }
+
+ context 'when ETag caching is not enabled for current route' do
+ let(:path) { '/gitlab-org/gitlab-ce/tree/master/noteable/issue/1/notes' }
+
+ before do
+ mock_app_response
+ end
+
+ it 'does not add ETag header' do
+ _, headers, _ = middleware.call(build_env(path, if_none_match))
+
+ expect(headers['ETag']).to be_nil
+ end
+
+ it 'passes status code from app' do
+ status, _, _ = middleware.call(build_env(path, if_none_match))
+
+ expect(status).to eq app_status_code
+ end
+ end
+
+ context 'when there is no ETag in store for given resource' do
+ let(:path) { enabled_path }
+
+ before do
+ mock_app_response
+ mock_value_in_store(nil)
+ end
+
+ it 'generates ETag' do
+ expect_any_instance_of(Gitlab::EtagCaching::Store)
+ .to receive(:touch).and_return('123')
+
+ middleware.call(build_env(path, if_none_match))
+ end
+
+ context 'when If-None-Match header was specified' do
+ let(:if_none_match) { 'W/"abc"' }
+
+ it 'tracks "etag_caching_key_not_found" event' do
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_middleware_used)
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_key_not_found)
+
+ middleware.call(build_env(path, if_none_match))
+ end
+ end
+ end
+
+ context 'when there is ETag in store for given resource' do
+ let(:path) { enabled_path }
+
+ before do
+ mock_app_response
+ mock_value_in_store('123')
+ end
+
+ it 'returns this value as header' do
+ _, headers, _ = middleware.call(build_env(path, if_none_match))
+
+ expect(headers['ETag']).to eq 'W/"123"'
+ end
+ end
+
+ context 'when If-None-Match header matches ETag in store' do
+ let(:path) { enabled_path }
+ let(:if_none_match) { 'W/"123"' }
+
+ before do
+ mock_value_in_store('123')
+ end
+
+ it 'does not call app' do
+ expect(app).not_to receive(:call)
+
+ middleware.call(build_env(path, if_none_match))
+ end
+
+ it 'returns status code 304' do
+ status, _, _ = middleware.call(build_env(path, if_none_match))
+
+ expect(status).to eq 304
+ end
+
+ it 'tracks "etag_caching_cache_hit" event' do
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_middleware_used)
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_cache_hit)
+
+ middleware.call(build_env(path, if_none_match))
+ end
+
+ context 'when polling is disabled' do
+ before do
+ allow(Gitlab::PollingInterval).to receive(:polling_enabled?).
+ and_return(false)
+ end
+
+ it 'returns status code 429' do
+ status, _, _ = middleware.call(build_env(path, if_none_match))
+
+ expect(status).to eq 429
+ end
+ end
+ end
+
+ context 'when If-None-Match header does not match ETag in store' do
+ let(:path) { enabled_path }
+ let(:if_none_match) { 'W/"abc"' }
+
+ before do
+ mock_value_in_store('123')
+ end
+
+ it 'calls app' do
+ expect(app).to receive(:call).and_return([app_status_code, {}, ['body']])
+
+ middleware.call(build_env(path, if_none_match))
+ end
+
+ it 'tracks "etag_caching_resource_changed" event' do
+ mock_app_response
+
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_middleware_used)
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_resource_changed)
+
+ middleware.call(build_env(path, if_none_match))
+ end
+ end
+
+ context 'when If-None-Match header is not specified' do
+ let(:path) { enabled_path }
+
+ before do
+ mock_value_in_store('123')
+ mock_app_response
+ end
+
+ it 'tracks "etag_caching_header_missing" event' do
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_middleware_used)
+ expect(Gitlab::Metrics).to receive(:add_event)
+ .with(:etag_caching_header_missing)
+
+ middleware.call(build_env(path, if_none_match))
+ end
+ end
+
+ def mock_app_response
+ allow(app).to receive(:call).and_return([app_status_code, {}, ['body']])
+ end
+
+ def mock_value_in_store(value)
+ allow_any_instance_of(Gitlab::EtagCaching::Store)
+ .to receive(:get).and_return(value)
+ end
+
+ def build_env(path, if_none_match)
+ {
+ 'PATH_INFO' => path,
+ 'HTTP_IF_NONE_MATCH' => if_none_match
+ }
+ end
+end
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index f4703dc704f..5d416c9eec3 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::Gfm::ReferenceRewriter do
let(:text) { 'some text' }
- let(:old_project) { create(:project, name: 'old') }
- let(:new_project) { create(:project, name: 'new') }
+ let(:old_project) { create(:empty_project, name: 'old-project') }
+ let(:new_project) { create(:empty_project, name: 'new-project') }
let(:user) { create(:user) }
before { old_project.team << [user, :reporter] }
diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
index 6eca33f9fee..c3016f63ebf 100644
--- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::Gfm::UploadsRewriter do
let(:user) { create(:user) }
- let(:old_project) { create(:project) }
- let(:new_project) { create(:project) }
+ let(:old_project) { create(:empty_project) }
+ let(:new_project) { create(:empty_project) }
let(:rewriter) { described_class.new(text, old_project, user) }
context 'text contains links to uploads' do
diff --git a/spec/lib/gitlab/git/blob_snippet_spec.rb b/spec/lib/gitlab/git/blob_snippet_spec.rb
index 79b1311ac91..d6d365f6492 100644
--- a/spec/lib/gitlab/git/blob_snippet_spec.rb
+++ b/spec/lib/gitlab/git/blob_snippet_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
describe Gitlab::Git::BlobSnippet, seed_helper: true do
- describe :data do
+ describe '#data' do
context 'empty lines' do
let(:snippet) { Gitlab::Git::BlobSnippet.new('master', nil, nil, nil) }
@@ -11,7 +11,7 @@ describe Gitlab::Git::BlobSnippet, seed_helper: true do
end
context 'present lines' do
- let(:snippet) { Gitlab::Git::BlobSnippet.new('master', ['wow', 'much'], 1, 'wow.rb') }
+ let(:snippet) { Gitlab::Git::BlobSnippet.new('master', %w(wow much), 1, 'wow.rb') }
it { expect(snippet.data).to eq("wow\nmuch") }
end
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 84f79ec2391..b883526151e 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -5,7 +5,7 @@ require "spec_helper"
describe Gitlab::Git::Blob, seed_helper: true do
let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
- describe :initialize do
+ describe 'initialize' do
let(:blob) { Gitlab::Git::Blob.new(name: 'test') }
it 'handles nil data' do
@@ -15,7 +15,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
- describe :find do
+ describe '.find' do
context 'file in subdir' do
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb") }
@@ -101,7 +101,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
- describe :raw do
+ describe '.raw' do
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
it { expect(raw_blob.id).to eq(SeedRepo::RubyBlob::ID) }
it { expect(raw_blob.data[0..10]).to eq("require \'fi") }
@@ -222,192 +222,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
end
- describe :commit do
- let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
-
- let(:commit_options) do
- {
- file: {
- content: 'Lorem ipsum...',
- path: 'documents/story.txt'
- },
- author: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- committer: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- commit: {
- message: 'Wow such commit',
- branch: 'fix-mode'
- }
- }
- end
-
- let(:commit_sha) { Gitlab::Git::Blob.commit(repository, commit_options) }
- let(:commit) { repository.lookup(commit_sha) }
-
- it 'should add file with commit' do
- # Commit message valid
- expect(commit.message).to eq('Wow such commit')
-
- tree = commit.tree.to_a.find { |tree| tree[:name] == 'documents' }
-
- # Directory was created
- expect(tree[:type]).to eq(:tree)
-
- # File was created
- expect(repository.lookup(tree[:oid]).first[:name]).to eq('story.txt')
- end
-
- describe "ref updating" do
- it 'creates a commit but does not udate a ref' do
- commit_opts = commit_options.tap{ |opts| opts[:commit][:update_ref] = false}
- commit_sha = Gitlab::Git::Blob.commit(repository, commit_opts)
- commit = repository.lookup(commit_sha)
-
- # Commit message valid
- expect(commit.message).to eq('Wow such commit')
-
- # Does not update any related ref
- expect(repository.lookup("fix-mode").oid).not_to eq(commit.oid)
- expect(repository.lookup("HEAD").oid).not_to eq(commit.oid)
- end
- end
-
- describe 'reject updates' do
- it 'should reject updates' do
- commit_options[:file][:update] = false
- commit_options[:file][:path] = 'files/executables/ls'
-
- expect{ commit_sha }.to raise_error('Filename already exists; update not allowed')
- end
- end
-
- describe 'file modes' do
- it 'should preserve file modes with commit' do
- commit_options[:file][:path] = 'files/executables/ls'
-
- entry = Gitlab::Git::Blob::find_entry_by_path(repository, commit.tree.oid, commit_options[:file][:path])
- expect(entry[:filemode]).to eq(0100755)
- end
- end
- end
-
- describe :rename do
- let(:repository) { Gitlab::Git::Repository.new(TEST_NORMAL_REPO_PATH) }
- let(:rename_options) do
- {
- file: {
- path: 'NEWCONTRIBUTING.md',
- previous_path: 'CONTRIBUTING.md',
- content: 'Lorem ipsum...',
- update: true
- },
- author: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- committer: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- commit: {
- message: 'Rename readme',
- branch: 'master'
- }
- }
- end
-
- let(:rename_options2) do
- {
- file: {
- content: 'Lorem ipsum...',
- path: 'bin/new_executable',
- previous_path: 'bin/executable',
- },
- author: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- committer: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- commit: {
- message: 'Updates toberenamed.txt',
- branch: 'master',
- update_ref: false
- }
- }
- end
-
- it 'maintains file permissions when renaming' do
- mode = 0o100755
-
- Gitlab::Git::Blob.rename(repository, rename_options2)
-
- expect(repository.rugged.index.get(rename_options2[:file][:path])[:mode]).to eq(mode)
- end
-
- it 'renames the file with commit and not change file permissions' do
- ref = rename_options[:commit][:branch]
-
- expect(repository.rugged.index.get('CONTRIBUTING.md')).not_to be_nil
- expect { Gitlab::Git::Blob.rename(repository, rename_options) }.to change { repository.commit_count(ref) }.by(1)
-
- expect(repository.rugged.index.get('CONTRIBUTING.md')).to be_nil
- expect(repository.rugged.index.get('NEWCONTRIBUTING.md')).not_to be_nil
- end
- end
-
- describe :remove do
- let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
-
- let(:commit_options) do
- {
- file: {
- path: 'README.md'
- },
- author: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- committer: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- commit: {
- message: 'Remove readme',
- branch: 'feature'
- }
- }
- end
-
- let(:commit_sha) { Gitlab::Git::Blob.remove(repository, commit_options) }
- let(:commit) { repository.lookup(commit_sha) }
- let(:blob) { Gitlab::Git::Blob.find(repository, commit_sha, "README.md") }
-
- it 'should remove file with commit' do
- # Commit message valid
- expect(commit.message).to eq('Remove readme')
-
- # File was removed
- expect(blob).to be_nil
- end
- end
-
- describe :lfs_pointers do
+ describe 'lfs_pointers' do
context 'file a valid lfs pointer' do
let(:blob) do
Gitlab::Git::Blob.find(
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index e1be6784c20..5cf4631fbfc 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -65,7 +65,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
context 'Class methods' do
- describe :find do
+ describe '.find' do
it "should return first head commit if without params" do
expect(Gitlab::Git::Commit.last(repository).id).to eq(
repository.raw.head.target.oid
@@ -103,7 +103,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :last_for_path do
+ describe '.last_for_path' do
context 'no path' do
subject { Gitlab::Git::Commit.last_for_path(repository, 'master') }
@@ -132,7 +132,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe "where" do
+ describe '.where' do
context 'path is empty string' do
subject do
commits = Gitlab::Git::Commit.where(
@@ -230,7 +230,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :between do
+ describe '.between' do
subject do
commits = Gitlab::Git::Commit.between(repository, SeedRepo::Commit::PARENT_ID, SeedRepo::Commit::ID)
commits.map { |c| c.id }
@@ -243,7 +243,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
it { is_expected.not_to include(SeedRepo::FirstCommit::ID) }
end
- describe :find_all do
+ describe '.find_all' do
context 'max_count' do
subject do
commits = Gitlab::Git::Commit.find_all(
@@ -304,7 +304,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :init_from_rugged do
+ describe '#init_from_rugged' do
let(:gitlab_commit) { Gitlab::Git::Commit.new(rugged_commit) }
subject { gitlab_commit }
@@ -314,7 +314,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :init_from_hash do
+ describe '#init_from_hash' do
let(:commit) { Gitlab::Git::Commit.new(sample_commit_hash) }
subject { commit }
@@ -329,7 +329,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :stats do
+ describe '#stats' do
subject { commit.stats }
describe '#additions' do
@@ -343,25 +343,25 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :to_diff do
+ describe '#to_diff' do
subject { commit.to_diff }
it { is_expected.not_to include "From #{SeedRepo::Commit::ID}" }
it { is_expected.to include 'diff --git a/files/ruby/popen.rb b/files/ruby/popen.rb'}
end
- describe :has_zero_stats? do
+ describe '#has_zero_stats?' do
it { expect(commit.has_zero_stats?).to eq(false) }
end
- describe :to_patch do
+ describe '#to_patch' do
subject { commit.to_patch }
it { is_expected.to include "From #{SeedRepo::Commit::ID}" }
it { is_expected.to include 'diff --git a/files/ruby/popen.rb b/files/ruby/popen.rb'}
end
- describe :to_hash do
+ describe '#to_hash' do
let(:hash) { commit.to_hash }
subject { hash }
@@ -373,7 +373,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
end
end
- describe :diffs do
+ describe '#diffs' do
subject { commit.diffs }
it { is_expected.to be_kind_of Gitlab::Git::DiffCollection }
@@ -381,7 +381,7 @@ describe Gitlab::Git::Commit, seed_helper: true do
it { expect(subject.first).to be_kind_of Gitlab::Git::Diff }
end
- describe :ref_names do
+ describe '#ref_names' do
let(:commit) { Gitlab::Git::Commit.find(repository, 'master') }
subject { commit.ref_names(repository) }
diff --git a/spec/lib/gitlab/git/compare_spec.rb b/spec/lib/gitlab/git/compare_spec.rb
index f66b68e4218..e28debe1494 100644
--- a/spec/lib/gitlab/git/compare_spec.rb
+++ b/spec/lib/gitlab/git/compare_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::Git::Compare, seed_helper: true do
let(:compare) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, false) }
let(:compare_straight) { Gitlab::Git::Compare.new(repository, SeedRepo::BigCommit::ID, SeedRepo::Commit::ID, true) }
- describe :commits do
+ describe '#commits' do
subject do
compare.commits.map(&:id)
end
@@ -42,7 +42,7 @@ describe Gitlab::Git::Compare, seed_helper: true do
end
end
- describe :diffs do
+ describe '#diffs' do
subject do
compare.diffs.map(&:new_path)
end
@@ -67,7 +67,7 @@ describe Gitlab::Git::Compare, seed_helper: true do
end
end
- describe :same do
+ describe '#same' do
subject do
compare.same
end
@@ -81,7 +81,7 @@ describe Gitlab::Git::Compare, seed_helper: true do
end
end
- describe :commits_straight do
+ describe '#commits', 'straight compare' do
subject do
compare_straight.commits.map(&:id)
end
@@ -94,7 +94,7 @@ describe Gitlab::Git::Compare, seed_helper: true do
it { is_expected.not_to include(SeedRepo::BigCommit::PARENT_ID) }
end
- describe :diffs_straight do
+ describe '#diffs', 'straight compare' do
subject do
compare_straight.diffs.map(&:new_path)
end
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index 4fa72c565ae..122c93dcd69 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -24,7 +24,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do
it { is_expected.to be_kind_of ::Array }
end
- describe :decorate! do
+ describe '#decorate!' do
let(:file_count) { 3 }
it 'modifies the array in place' do
@@ -302,7 +302,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do
end
end
- describe :each do
+ describe '#each' do
context 'when diff are too large' do
let(:collection) do
Gitlab::Git::DiffCollection.new([{ diff: 'a' * 204800 }])
@@ -365,7 +365,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do
end
context 'when go over safe limits on files' do
- let(:iterator) { [ fake_diff(1, 1) ] * 4 }
+ let(:iterator) { [fake_diff(1, 1)] * 4 }
before(:each) do
stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: max_lines })
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 4c55532d165..992126ef153 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -109,6 +109,43 @@ EOT
end
end
end
+
+ context 'using a Gitaly::CommitDiffResponse' do
+ let(:diff) do
+ described_class.new(
+ Gitaly::CommitDiffResponse.new(
+ to_path: ".gitmodules",
+ from_path: ".gitmodules",
+ old_mode: 0100644,
+ new_mode: 0100644,
+ from_id: '357406f3075a57708d0163752905cc1576fceacc',
+ to_id: '8e5177d718c561d36efde08bad36b43687ee6bf0',
+ raw_chunks: raw_chunks,
+ )
+ )
+ end
+
+ context 'with a small diff' do
+ let(:raw_chunks) { [@raw_diff_hash[:diff]] }
+
+ it 'initializes the diff' do
+ expect(diff.to_hash).to eq(@raw_diff_hash)
+ end
+
+ it 'does not prune the diff' do
+ expect(diff).not_to be_too_large
+ end
+ end
+
+ context 'using a diff that is too large' do
+ let(:raw_chunks) { ['a' * 204800] }
+
+ it 'prunes the diff' do
+ expect(diff.diff).to be_empty
+ expect(diff).to be_too_large
+ end
+ end
+ end
end
describe 'straight diffs' do
diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb
index d1f947b6850..3f279c21865 100644
--- a/spec/lib/gitlab/git/hook_spec.rb
+++ b/spec/lib/gitlab/git/hook_spec.rb
@@ -3,7 +3,7 @@ require 'fileutils'
describe Gitlab::Git::Hook, lib: true do
describe "#trigger" do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
def create_hook(name)
diff --git a/spec/lib/gitlab/git/index_spec.rb b/spec/lib/gitlab/git/index_spec.rb
new file mode 100644
index 00000000000..d0c7ca60ddc
--- /dev/null
+++ b/spec/lib/gitlab/git/index_spec.rb
@@ -0,0 +1,220 @@
+require 'spec_helper'
+
+describe Gitlab::Git::Index, seed_helper: true do
+ let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
+ let(:index) { described_class.new(repository) }
+
+ before do
+ index.read_tree(repository.lookup('master').tree)
+ end
+
+ describe '#create' do
+ let(:options) do
+ {
+ content: 'Lorem ipsum...',
+ file_path: 'documents/story.txt'
+ }
+ end
+
+ context 'when no file at that path exists' do
+ it 'creates the file in the index' do
+ index.create(options)
+
+ entry = index.get(options[:file_path])
+
+ expect(entry).not_to be_nil
+ expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
+ end
+ end
+
+ context 'when a file at that path exists' do
+ before do
+ options[:file_path] = 'files/executables/ls'
+ end
+
+ it 'raises an error' do
+ expect { index.create(options) }.to raise_error('Filename already exists')
+ end
+ end
+
+ context 'when content is in base64' do
+ before do
+ options[:content] = Base64.encode64(options[:content])
+ options[:encoding] = 'base64'
+ end
+
+ it 'decodes base64' do
+ index.create(options)
+
+ entry = index.get(options[:file_path])
+ expect(repository.lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content]))
+ end
+ end
+
+ context 'when content contains CRLF' do
+ before do
+ repository.autocrlf = :input
+ options[:content] = "Hello,\r\nWorld"
+ end
+
+ it 'converts to LF' do
+ index.create(options)
+
+ entry = index.get(options[:file_path])
+ expect(repository.lookup(entry[:oid]).content).to eq("Hello,\nWorld")
+ end
+ end
+ end
+
+ describe '#create_dir' do
+ let(:options) do
+ {
+ file_path: 'newdir'
+ }
+ end
+
+ context 'when no file or dir at that path exists' do
+ it 'creates the dir in the index' do
+ index.create_dir(options)
+
+ entry = index.get(options[:file_path] + '/.gitkeep')
+
+ expect(entry).not_to be_nil
+ end
+ end
+
+ context 'when a file at that path exists' do
+ before do
+ options[:file_path] = 'files/executables/ls'
+ end
+
+ it 'raises an error' do
+ expect { index.create_dir(options) }.to raise_error('Directory already exists as a file')
+ end
+ end
+
+ context 'when a directory at that path exists' do
+ before do
+ options[:file_path] = 'files/executables'
+ end
+
+ it 'raises an error' do
+ expect { index.create_dir(options) }.to raise_error('Directory already exists')
+ end
+ end
+ end
+
+ describe '#update' do
+ let(:options) do
+ {
+ content: 'Lorem ipsum...',
+ file_path: 'README.md'
+ }
+ end
+
+ context 'when no file at that path exists' do
+ before do
+ options[:file_path] = 'documents/story.txt'
+ end
+
+ it 'raises an error' do
+ expect { index.update(options) }.to raise_error("File doesn't exist")
+ end
+ end
+
+ context 'when a file at that path exists' do
+ it 'updates the file in the index' do
+ index.update(options)
+
+ entry = index.get(options[:file_path])
+
+ expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
+ end
+
+ it 'preserves file mode' do
+ options[:file_path] = 'files/executables/ls'
+
+ index.update(options)
+
+ entry = index.get(options[:file_path])
+
+ expect(entry[:mode]).to eq(0100755)
+ end
+ end
+ end
+
+ describe '#move' do
+ let(:options) do
+ {
+ content: 'Lorem ipsum...',
+ previous_path: 'README.md',
+ file_path: 'NEWREADME.md'
+ }
+ end
+
+ context 'when no file at that path exists' do
+ it 'raises an error' do
+ options[:previous_path] = 'documents/story.txt'
+
+ expect { index.move(options) }.to raise_error("File doesn't exist")
+ end
+ end
+
+ context 'when a file at that path exists' do
+ it 'removes the old file in the index' do
+ index.move(options)
+
+ entry = index.get(options[:previous_path])
+
+ expect(entry).to be_nil
+ end
+
+ it 'creates the new file in the index' do
+ index.move(options)
+
+ entry = index.get(options[:file_path])
+
+ expect(entry).not_to be_nil
+ expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
+ end
+
+ it 'preserves file mode' do
+ options[:previous_path] = 'files/executables/ls'
+
+ index.move(options)
+
+ entry = index.get(options[:file_path])
+
+ expect(entry[:mode]).to eq(0100755)
+ end
+ end
+ end
+
+ describe '#delete' do
+ let(:options) do
+ {
+ file_path: 'README.md'
+ }
+ end
+
+ context 'when no file at that path exists' do
+ before do
+ options[:file_path] = 'documents/story.txt'
+ end
+
+ it 'raises an error' do
+ expect { index.delete(options) }.to raise_error("File doesn't exist")
+ end
+ end
+
+ context 'when a file at that path exists' do
+ it 'removes the file in the index' do
+ index.delete(options)
+
+ entry = index.get(options[:file_path])
+
+ expect(entry).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 2a915bf426f..d4b7684adfd 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -47,7 +47,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe :branch_names do
+ describe '#branch_names' do
subject { repository.branch_names }
it 'has SeedRepo::Repo::BRANCHES.size elements' do
@@ -57,7 +57,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.not_to include("branch-from-space") }
end
- describe :tag_names do
+ describe '#tag_names' do
subject { repository.tag_names }
it { is_expected.to be_kind_of Array }
@@ -78,49 +78,69 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { expect(metadata['ArchivePath']).to end_with extenstion }
end
- describe :archive do
+ describe '#archive_prefix' do
+ let(:project_name) { 'project-name'}
+
+ before do
+ expect(repository).to receive(:name).once.and_return(project_name)
+ end
+
+ it 'returns parameterised string for a ref containing slashes' do
+ prefix = repository.archive_prefix('test/branch', 'SHA')
+
+ expect(prefix).to eq("#{project_name}-test-branch-SHA")
+ end
+
+ it 'returns correct string for a ref containing dots' do
+ prefix = repository.archive_prefix('test.branch', 'SHA')
+
+ expect(prefix).to eq("#{project_name}-test.branch-SHA")
+ end
+ end
+
+ describe '#archive' do
let(:metadata) { repository.archive_metadata('master', '/tmp') }
it_should_behave_like 'archive check', '.tar.gz'
end
- describe :archive_zip do
+ describe '#archive_zip' do
let(:metadata) { repository.archive_metadata('master', '/tmp', 'zip') }
it_should_behave_like 'archive check', '.zip'
end
- describe :archive_bz2 do
+ describe '#archive_bz2' do
let(:metadata) { repository.archive_metadata('master', '/tmp', 'tbz2') }
it_should_behave_like 'archive check', '.tar.bz2'
end
- describe :archive_fallback do
+ describe '#archive_fallback' do
let(:metadata) { repository.archive_metadata('master', '/tmp', 'madeup') }
it_should_behave_like 'archive check', '.tar.gz'
end
- describe :size do
+ describe '#size' do
subject { repository.size }
it { is_expected.to be < 2 }
end
- describe :has_commits? do
+ describe '#has_commits?' do
it { expect(repository.has_commits?).to be_truthy }
end
- describe :empty? do
+ describe '#empty?' do
it { expect(repository.empty?).to be_falsey }
end
- describe :bare? do
+ describe '#bare?' do
it { expect(repository.bare?).to be_truthy }
end
- describe :heads do
+ describe '#heads' do
let(:heads) { repository.heads }
subject { heads }
@@ -147,7 +167,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe :ref_names do
+ describe '#ref_names' do
let(:ref_names) { repository.ref_names }
subject { ref_names }
@@ -164,7 +184,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe :search_files do
+ describe '#search_files' do
let(:results) { repository.search_files('rails', 'master') }
subject { results }
@@ -200,7 +220,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- context :submodules do
+ context '#submodules' do
let(:repository) { Gitlab::Git::Repository.new(TEST_REPO_PATH) }
context 'where repo has submodules' do
@@ -264,7 +284,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe :commit_count do
+ describe '#commit_count' do
it { expect(repository.commit_count("master")).to eq(25) }
it { expect(repository.commit_count("feature")).to eq(9) }
end
@@ -493,7 +513,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe "#remote_add" do
before(:all) do
@repo = Gitlab::Git::Repository.new(TEST_MUTABLE_REPO_PATH)
- @repo.remote_add("new_remote", SeedHelper::GITLAB_URL)
+ @repo.remote_add("new_remote", SeedHelper::GITLAB_GIT_TEST_REPO_URL)
end
it "should add the remote" do
@@ -529,7 +549,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
commit_with_new_name = nil
rename_commit = nil
- before(:all) do
+ before(:context) do
# Add new commits so that there's a renamed file in the commit history
repo = Gitlab::Git::Repository.new(TEST_REPO_PATH).rugged
@@ -538,49 +558,119 @@ describe Gitlab::Git::Repository, seed_helper: true do
commit_with_new_name = new_commit_edit_new_file(repo)
end
+ after(:context) do
+ # Erase our commits so other tests get the original repo
+ repo = Gitlab::Git::Repository.new(TEST_REPO_PATH).rugged
+ repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
+ end
+
context "where 'follow' == true" do
- options = { ref: "master", follow: true }
+ let(:options) { { ref: "master", follow: true } }
context "and 'path' is a directory" do
- let(:log_commits) do
- repository.log(options.merge(path: "encoding"))
- end
+ it "does not follow renames" do
+ log_commits = repository.log(options.merge(path: "encoding"))
- it "should not follow renames" do
- expect(log_commits).to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).not_to include(commit_with_old_name)
+ aggregate_failures do
+ expect(log_commits).to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).not_to include(commit_with_old_name)
+ end
end
end
context "and 'path' is a file that matches the new filename" do
- let(:log_commits) do
- repository.log(options.merge(path: "encoding/CHANGELOG"))
+ context 'without offset' do
+ it "follows renames" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG"))
+
+ aggregate_failures do
+ expect(log_commits).to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
end
- it "should follow renames" do
- expect(log_commits).to include(commit_with_new_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).to include(commit_with_old_name)
+ context 'with offset=1' do
+ it "follows renames and skip the latest commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1))
+
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
+ end
+
+ context 'with offset=1', 'and limit=1' do
+ it "follows renames, skip the latest commit and return only one commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 1))
+
+ expect(log_commits).to contain_exactly(rename_commit)
+ end
+ end
+
+ context 'with offset=1', 'and limit=2' do
+ it "follows renames, skip the latest commit and return only two commits" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 1, limit: 2))
+
+ aggregate_failures do
+ expect(log_commits).to contain_exactly(rename_commit, commit_with_old_name)
+ end
+ end
+ end
+
+ context 'with offset=2' do
+ it "follows renames and skip the latest commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2))
+
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).not_to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
+ end
+
+ context 'with offset=2', 'and limit=1' do
+ it "follows renames, skip the two latest commit and return only one commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 1))
+
+ expect(log_commits).to contain_exactly(commit_with_old_name)
+ end
+ end
+
+ context 'with offset=2', 'and limit=2' do
+ it "follows renames, skip the two latest commit and return only one commit" do
+ log_commits = repository.log(options.merge(path: "encoding/CHANGELOG", offset: 2, limit: 2))
+
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).not_to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
+ end
end
end
context "and 'path' is a file that matches the old filename" do
- let(:log_commits) do
- repository.log(options.merge(path: "CHANGELOG"))
- end
+ it "does not follow renames" do
+ log_commits = repository.log(options.merge(path: "CHANGELOG"))
- it "should not follow renames" do
- expect(log_commits).to include(commit_with_old_name)
- expect(log_commits).to include(rename_commit)
- expect(log_commits).not_to include(commit_with_new_name)
+ aggregate_failures do
+ expect(log_commits).not_to include(commit_with_new_name)
+ expect(log_commits).to include(rename_commit)
+ expect(log_commits).to include(commit_with_old_name)
+ end
end
end
context "unknown ref" do
- let(:log_commits) { repository.log(options.merge(ref: 'unknown')) }
+ it "returns an empty array" do
+ log_commits = repository.log(options.merge(ref: 'unknown'))
- it "should return empty" do
expect(log_commits).to eq([])
end
end
@@ -681,8 +771,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
commits = repository.log(options)
expect(commits.size).to be > 0
- satisfy do
- commits.all? { |commit| commit.created_at >= options[:after] }
+ expect(commits).to satisfy do |commits|
+ commits.all? { |commit| commit.time >= options[:after] }
end
end
end
@@ -694,16 +784,29 @@ describe Gitlab::Git::Repository, seed_helper: true do
commits = repository.log(options)
expect(commits.size).to be > 0
- satisfy do
- commits.all? { |commit| commit.created_at <= options[:before] }
+ expect(commits).to satisfy do |commits|
+ commits.all? { |commit| commit.time <= options[:before] }
end
end
end
- after(:all) do
- # Erase our commits so other tests get the original repo
- repo = Gitlab::Git::Repository.new(TEST_REPO_PATH).rugged
- repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID)
+ context 'when multiple paths are provided' do
+ let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
+
+ def commit_files(commit)
+ commit.diff(commit.parent_ids.first).deltas.flat_map do |delta|
+ [delta.old_file[:path], delta.new_file[:path]].uniq.compact
+ end
+ end
+
+ it 'only returns commits matching at least one path' do
+ commits = repository.log(options)
+
+ expect(commits.size).to be > 0
+ expect(commits).to satisfy do |commits|
+ commits.none? { |commit| (commit_files(commit) & options[:path]).empty? }
+ end
+ end
end
end
@@ -746,6 +849,32 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.to eq(17) }
end
+ describe '#count_commits' do
+ context 'with after timestamp' do
+ it 'returns the number of commits after timestamp' do
+ options = { ref: 'master', limit: nil, after: Time.iso8601('2013-03-03T20:15:01+00:00') }
+
+ expect(repository.count_commits(options)).to eq(25)
+ end
+ end
+
+ context 'with before timestamp' do
+ it 'returns the number of commits after timestamp' do
+ options = { ref: 'feature', limit: nil, before: Time.iso8601('2015-03-03T20:15:01+00:00') }
+
+ expect(repository.count_commits(options)).to eq(9)
+ end
+ end
+
+ context 'with path' do
+ it 'returns the number of commits with path ' do
+ options = { ref: 'master', limit: nil, path: "encoding" }
+
+ expect(repository.count_commits(options)).to eq(2)
+ end
+ end
+ end
+
describe "branch_names_contains" do
subject { repository.branch_names_contains(SeedRepo::LastCommit::ID) }
@@ -844,81 +973,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#mkdir' do
- let(:commit_options) do
- {
- author: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- committer: {
- email: 'user@example.com',
- name: 'Test User',
- time: Time.now
- },
- commit: {
- message: 'Test message',
- branch: 'refs/heads/fix',
- }
- }
- end
-
- def generate_diff_for_path(path)
- "diff --git a/#{path}/.gitkeep b/#{path}/.gitkeep
-new file mode 100644
-index 0000000..e69de29
---- /dev/null
-+++ b/#{path}/.gitkeep\n"
- end
-
- shared_examples 'mkdir diff check' do |path, expected_path|
- it 'creates a directory' do
- result = repository.mkdir(path, commit_options)
- expect(result).not_to eq(nil)
-
- # Verify another mkdir doesn't create a directory that already exists
- expect{ repository.mkdir(path, commit_options) }.to raise_error('Directory already exists')
- end
- end
-
- describe 'creates a directory in root directory' do
- it_should_behave_like 'mkdir diff check', 'new_dir', 'new_dir'
- end
-
- describe 'creates a directory in subdirectory' do
- it_should_behave_like 'mkdir diff check', 'files/ruby/test', 'files/ruby/test'
- end
-
- describe 'creates a directory in subdirectory with a slash' do
- it_should_behave_like 'mkdir diff check', '/files/ruby/test2', 'files/ruby/test2'
- end
-
- describe 'creates a directory in subdirectory with multiple slashes' do
- it_should_behave_like 'mkdir diff check', '//files/ruby/test3', 'files/ruby/test3'
- end
-
- describe 'handles relative paths' do
- it_should_behave_like 'mkdir diff check', 'files/ruby/../test_relative', 'files/test_relative'
- end
-
- describe 'creates nested directories' do
- it_should_behave_like 'mkdir diff check', 'files/missing/test', 'files/missing/test'
- end
-
- it 'does not attempt to create a directory with invalid relative path' do
- expect{ repository.mkdir('../files/missing/test', commit_options) }.to raise_error('Invalid path')
- end
-
- it 'does not attempt to overwrite a file' do
- expect{ repository.mkdir('README.md', commit_options) }.to raise_error('Directory already exists as a file')
- end
-
- it 'does not attempt to overwrite a directory' do
- expect{ repository.mkdir('files', commit_options) }.to raise_error('Directory already exists')
- end
- end
-
describe "#ls_files" do
let(:master_file_paths) { repository.ls_files("master") }
let(:not_existed_branch) { repository.ls_files("not_existed_branch") }
diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb
index 1f9c987be0b..d48629a296d 100644
--- a/spec/lib/gitlab/git/rev_list_spec.rb
+++ b/spec/lib/gitlab/git/rev_list_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Git::RevList, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context "validations" do
described_class::ALLOWED_VARIABLES.each do |var|
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 688e2a75373..82685712b5b 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::Git::Tree, seed_helper: true do
it { expect(tree.select(&:file?).size).to eq(10) }
it { expect(tree.select(&:submodule?).size).to eq(2) }
- describe :dir do
+ describe '#dir?' do
let(:dir) { tree.select(&:dir?).first }
it { expect(dir).to be_kind_of Gitlab::Git::Tree }
@@ -19,6 +19,7 @@ describe Gitlab::Git::Tree, seed_helper: true do
it { expect(dir.commit_id).to eq(SeedRepo::Commit::ID) }
it { expect(dir.name).to eq('encoding') }
it { expect(dir.path).to eq('encoding') }
+ it { expect(dir.mode).to eq('40000') }
context :subdir do
let(:subdir) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID, 'files').first }
@@ -41,7 +42,7 @@ describe Gitlab::Git::Tree, seed_helper: true do
end
end
- describe :file do
+ describe '#file?' do
let(:file) { tree.select(&:file?).first }
it { expect(file).to be_kind_of Gitlab::Git::Tree }
@@ -50,21 +51,21 @@ describe Gitlab::Git::Tree, seed_helper: true do
it { expect(file.name).to eq('.gitignore') }
end
- describe :readme do
+ describe '#readme?' do
let(:file) { tree.select(&:readme?).first }
it { expect(file).to be_kind_of Gitlab::Git::Tree }
it { expect(file.name).to eq('README.md') }
end
- describe :contributing do
+ describe '#contributing?' do
let(:file) { tree.select(&:contributing?).first }
it { expect(file).to be_kind_of Gitlab::Git::Tree }
it { expect(file.name).to eq('CONTRIBUTING.md') }
end
- describe :submodule do
+ describe '#submodule?' do
let(:submodule) { tree.select(&:submodule?).first }
it { expect(submodule).to be_kind_of Gitlab::Git::Tree }
diff --git a/spec/lib/gitlab/git/util_spec.rb b/spec/lib/gitlab/git/util_spec.rb
index 8d43b570e98..bcca4d4c746 100644
--- a/spec/lib/gitlab/git/util_spec.rb
+++ b/spec/lib/gitlab/git/util_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Git::Util do
- describe :count_lines do
+ describe '#count_lines' do
[
["", 0],
["foo", 1],
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 44b84afde47..703b41f95ac 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::GitAccess, lib: true do
let(:access) { Gitlab::GitAccess.new(actor, project, 'web', authentication_abilities: authentication_abilities) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:actor) { user }
let(:authentication_abilities) do
@@ -88,14 +88,12 @@ describe Gitlab::GitAccess, lib: true do
end
context 'when project is public' do
- let(:public_project) { create(:project, :public) }
+ let(:public_project) { create(:project, :public, :repository) }
let(:guest_access) { Gitlab::GitAccess.new(nil, public_project, 'web', authentication_abilities: []) }
subject { guest_access.check('git-upload-pack', '_any') }
context 'when repository is enabled' do
it 'give access to download code' do
- public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::ENABLED)
-
expect(subject.allowed?).to be_truthy
end
end
@@ -124,19 +122,19 @@ describe Gitlab::GitAccess, lib: true do
context 'when unauthorized' do
context 'from public project' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
it { expect(subject).to be_allowed }
end
context 'from internal project' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :internal, :repository) }
it { expect(subject).not_to be_allowed }
end
context 'from private project' do
- let(:project) { create(:project, :private) }
+ let(:project) { create(:project, :private, :repository) }
it { expect(subject).not_to be_allowed }
end
@@ -148,7 +146,7 @@ describe Gitlab::GitAccess, lib: true do
let(:authentication_abilities) { build_authentication_abilities }
describe 'owner' do
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:project, :repository, namespace: user.namespace) }
context 'pull code' do
it { expect(subject).to be_allowed }
@@ -185,7 +183,7 @@ describe Gitlab::GitAccess, lib: true do
describe '#check_push_access!' do
before { merge_into_protected_branch }
- let(:unprotected_branch) { FFaker::Internet.user_name }
+ let(:unprotected_branch) { 'unprotected_branch' }
let(:changes) do
{ push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow",
@@ -201,7 +199,9 @@ describe Gitlab::GitAccess, lib: true do
def stub_git_hooks
# Running the `pre-receive` hook is expensive, and not necessary for this test.
- allow_any_instance_of(GitHooksService).to receive(:execute).and_yield
+ allow_any_instance_of(GitHooksService).to receive(:execute) do |service, &block|
+ block.call(service)
+ end
end
def merge_into_protected_branch
@@ -209,7 +209,12 @@ describe Gitlab::GitAccess, lib: true do
stub_git_hooks
project.repository.add_branch(user, unprotected_branch, 'feature')
target_branch = project.repository.lookup('feature')
- source_branch = project.repository.commit_file(user, FFaker::InternetSE.login_user_name, FFaker::HipsterIpsum.paragraph, FFaker::HipsterIpsum.sentence, unprotected_branch, false)
+ source_branch = project.repository.create_file(
+ user,
+ 'John Doe',
+ 'This is the file content',
+ message: 'This is a good commit message',
+ branch_name: unprotected_branch)
rugged = project.repository.rugged
author = { email: "email@example.com", time: Time.now, name: "Example Git User" }
@@ -228,11 +233,18 @@ describe Gitlab::GitAccess, lib: true do
else
project.team << [user, role]
end
+ end
+
+ permissions_matrix[role].each do |action, allowed|
+ context action do
+ subject { access.send(:check_push_access!, changes[action]) }
- permissions_matrix[role].each do |action, allowed|
- context action do
- subject { access.send(:check_push_access!, changes[action]) }
- it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
+ it do
+ if allowed
+ expect { subject }.not_to raise_error
+ else
+ expect { subject }.to raise_error(Gitlab::GitAccess::UnauthorizedError)
+ end
end
end
end
@@ -297,7 +309,7 @@ describe Gitlab::GitAccess, lib: true do
}
}
- [['feature', 'exact'], ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
+ [%w(feature exact), ['feat*', 'wildcard']].each do |protected_branch_name, protected_branch_type|
context do
before { create(:protected_branch, name: protected_branch_name, project: project) }
@@ -364,19 +376,19 @@ describe Gitlab::GitAccess, lib: true do
context 'when unauthorized' do
context 'to public project' do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:project, :public, :repository) }
it { expect(subject).not_to be_allowed }
end
context 'to internal project' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :internal, :repository) }
it { expect(subject).not_to be_allowed }
end
context 'to private project' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :private, :repository) }
it { expect(subject).not_to be_allowed }
end
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index a5d172233cc..1ae293416e4 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::GitAccessWiki, lib: true do
let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:authentication_abilities) do
[
@@ -36,8 +36,6 @@ describe Gitlab::GitAccessWiki, lib: true do
context 'when wiki feature is enabled' do
it 'give access to download wiki code' do
- project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::ENABLED)
-
expect(subject.allowed?).to be_truthy
end
end
diff --git a/spec/lib/gitlab/git_spec.rb b/spec/lib/gitlab/git_spec.rb
index 219198eff60..36f0e6507c8 100644
--- a/spec/lib/gitlab/git_spec.rb
+++ b/spec/lib/gitlab/git_spec.rb
@@ -1,25 +1,12 @@
require 'spec_helper'
describe Gitlab::Git, lib: true do
- let(:committer_email) { FFaker::Internet.email }
-
- # I have to remove periods from the end of the name
- # This happened when the user's name had a suffix (i.e. "Sr.")
- # This seems to be what git does under the hood. For example, this commit:
- #
- # $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?'
- #
- # results in this:
- #
- # $ git show --pretty
- # ...
- # Author: Foo Sr <foo@example.com>
- # ...
- let(:committer_name) { FFaker::Name.name.chomp("\.") }
+ let(:committer_email) { 'user@example.org' }
+ let(:committer_name) { 'John Doe' }
describe 'committer_hash' do
it "returns a hash containing the given email and name" do
- committer_hash = Gitlab::Git::committer_hash(email: committer_email, name: committer_name)
+ committer_hash = Gitlab::Git.committer_hash(email: committer_email, name: committer_name)
expect(committer_hash[:email]).to eq(committer_email)
expect(committer_hash[:name]).to eq(committer_name)
@@ -28,7 +15,7 @@ describe Gitlab::Git, lib: true do
context 'when email is nil' do
it "returns nil" do
- committer_hash = Gitlab::Git::committer_hash(email: nil, name: committer_name)
+ committer_hash = Gitlab::Git.committer_hash(email: nil, name: committer_name)
expect(committer_hash).to be_nil
end
@@ -36,7 +23,7 @@ describe Gitlab::Git, lib: true do
context 'when name is nil' do
it "returns nil" do
- committer_hash = Gitlab::Git::committer_hash(email: committer_email, name: nil)
+ committer_hash = Gitlab::Git.committer_hash(email: committer_email, name: nil)
expect(committer_hash).to be_nil
end
diff --git a/spec/lib/gitlab/gitaly_client/commit_spec.rb b/spec/lib/gitlab/gitaly_client/commit_spec.rb
new file mode 100644
index 00000000000..4684b1d1ac0
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/commit_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::Commit do
+ describe '.diff_from_parent' do
+ let(:diff_stub) { double('Gitaly::Diff::Stub') }
+ let(:project) { create(:project, :repository) }
+ let(:repository_message) { Gitaly::Repository.new(path: project.repository.path) }
+ let(:commit) { project.commit('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
+
+ before do
+ allow(Gitaly::Diff::Stub).to receive(:new).and_return(diff_stub)
+ allow(diff_stub).to receive(:commit_diff).and_return([])
+ end
+
+ context 'when a commit has a parent' do
+ it 'sends an RPC request with the parent ID as left commit' do
+ request = Gitaly::CommitDiffRequest.new(
+ repository: repository_message,
+ left_commit_id: 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660',
+ right_commit_id: commit.id,
+ )
+
+ expect(diff_stub).to receive(:commit_diff).with(request)
+
+ described_class.diff_from_parent(commit)
+ end
+ end
+
+ context 'when a commit does not have a parent' do
+ it 'sends an RPC request with empty tree ref as left commit' do
+ initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
+ request = Gitaly::CommitDiffRequest.new(
+ repository: repository_message,
+ left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
+ right_commit_id: initial_commit.id,
+ )
+
+ expect(diff_stub).to receive(:commit_diff).with(request)
+
+ described_class.diff_from_parent(initial_commit)
+ end
+ end
+
+ it 'returns a Gitlab::Git::DiffCollection' do
+ ret = described_class.diff_from_parent(commit)
+
+ expect(ret).to be_kind_of(Gitlab::Git::DiffCollection)
+ end
+
+ it 'passes options to Gitlab::Git::DiffCollection' do
+ options = { max_files: 31, max_lines: 13 }
+
+ expect(Gitlab::Git::DiffCollection).to receive(:new).with([], options)
+
+ described_class.diff_from_parent(commit, options)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client/notifications_spec.rb b/spec/lib/gitlab/gitaly_client/notifications_spec.rb
new file mode 100644
index 00000000000..bb5d93994ad
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/notifications_spec.rb
@@ -0,0 +1,13 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::Notifications do
+ describe '#post_receive' do
+ it 'sends a post_receive message' do
+ repo_path = create(:empty_project).repository.path_to_repo
+ expect_any_instance_of(Gitaly::Notifications::Stub).
+ to receive(:post_receive).with(post_receive_request_with_repo_path(repo_path))
+
+ described_class.new(repo_path).post_receive
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
new file mode 100644
index 00000000000..55fcf91fb6e
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient, lib: true do
+ describe '.new_channel' do
+ context 'when passed a UNIX socket address' do
+ it 'passes the address as-is to GRPC::Core::Channel initializer' do
+ address = 'unix:/tmp/gitaly.sock'
+
+ expect(GRPC::Core::Channel).to receive(:new).with(address, any_args)
+
+ described_class.new_channel(address)
+ end
+ end
+
+ context 'when passed a TCP address' do
+ it 'strips tcp:// prefix before passing it to GRPC::Core::Channel initializer' do
+ address = 'localhost:9876'
+ prefixed_address = "tcp://#{address}"
+
+ expect(GRPC::Core::Channel).to receive(:new).with(address, any_args)
+
+ described_class.new_channel(prefixed_address)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/branch_formatter_spec.rb b/spec/lib/gitlab/github_import/branch_formatter_spec.rb
index 462caa5b5fe..3a31f93efa5 100644
--- a/spec/lib/gitlab/github_import/branch_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/branch_formatter_spec.rb
@@ -1,32 +1,32 @@
require 'spec_helper'
describe Gitlab::GithubImport::BranchFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:commit) { create(:commit, project: project) }
let(:repo) { double }
let(:raw) do
{
- ref: 'feature',
+ ref: 'branch-merged',
repo: repo,
sha: commit.id
}
end
describe '#exists?' do
- it 'returns true when both branch, and commit exists' do
+ it 'returns true when branch exists and commit is part of the branch' do
branch = described_class.new(project, double(raw))
expect(branch.exists?).to eq true
end
- it 'returns false when branch does not exist' do
- branch = described_class.new(project, double(raw.merge(ref: 'removed-branch')))
+ it 'returns false when branch exists and commit is not part of the branch' do
+ branch = described_class.new(project, double(raw.merge(ref: 'feature')))
expect(branch.exists?).to eq false
end
- it 'returns false when commit does not exist' do
- branch = described_class.new(project, double(raw.merge(sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b')))
+ it 'returns false when branch does not exist' do
+ branch = described_class.new(project, double(raw.merge(ref: 'removed-branch')))
expect(branch.exists?).to eq false
end
diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
index c520a9c53ad..cc38872e426 100644
--- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
@@ -1,8 +1,9 @@
require 'spec_helper'
describe Gitlab::GithubImport::CommentFormatter, lib: true do
- let(:project) { create(:project) }
- let(:octocat) { double(id: 123456, login: 'octocat') }
+ let(:client) { double }
+ let(:project) { create(:empty_project) }
+ let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') }
let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') }
let(:base) do
@@ -16,7 +17,11 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
}
end
- subject(:comment) { described_class.new(project, raw)}
+ subject(:comment) { described_class.new(project, raw, client) }
+
+ before do
+ allow(client).to receive(:user).and_return(octocat)
+ end
describe '#attributes' do
context 'when do not reference a portion of the diff' do
@@ -69,8 +74,15 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
context 'when author is a GitLab user' do
let(:raw) { double(base.merge(user: octocat)) }
- it 'returns GitLab user id as author_id' do
+ it 'returns GitLab user id associated with GitHub id as author_id' do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
+
+ expect(comment.attributes.fetch(:author_id)).to eq gl_user.id
+ end
+
+ it 'returns GitLab user id associated with GitHub email as author_id' do
+ gl_user = create(:user, email: octocat.email)
+
expect(comment.attributes.fetch(:author_id)).to eq gl_user.id
end
diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb
index 72421832ffc..9d5e20841b5 100644
--- a/spec/lib/gitlab/github_import/importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer_spec.rb
@@ -44,6 +44,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound)
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error)
+ allow_any_instance_of(Octokit::Client).to receive(:user).and_return(octocat)
allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label1, label2])
allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone])
allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2])
@@ -53,9 +54,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil }))
allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2])
end
- let(:octocat) { double(id: 123456, login: 'octocat') }
- let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
- let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
+
let(:label1) do
double(
name: 'Bug',
@@ -125,31 +124,6 @@ describe Gitlab::GithubImport::Importer, lib: true do
)
end
- let(:repository) { double(id: 1, fork: false) }
- let(:source_sha) { create(:commit, project: project).id }
- let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) }
- let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
- let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) }
- let(:pull_request) do
- double(
- number: 1347,
- milestone: nil,
- state: 'open',
- title: 'New feature',
- body: 'Please pull these awesome changes',
- head: source_branch,
- base: target_branch,
- assignee: nil,
- user: octocat,
- created_at: created_at,
- updated_at: updated_at,
- closed_at: nil,
- merged_at: nil,
- url: "#{api_root}/repos/octocat/Hello-World/pulls/1347",
- labels: [double(name: 'Label #2')]
- )
- end
-
let(:release1) do
double(
tag_name: 'v1.0.0',
@@ -174,12 +148,14 @@ describe Gitlab::GithubImport::Importer, lib: true do
)
end
+ subject { described_class.new(project) }
+
it 'returns true' do
- expect(described_class.new(project).execute).to eq true
+ expect(subject.execute).to eq true
end
it 'does not raise an error' do
- expect { described_class.new(project).execute }.not_to raise_error
+ expect { subject.execute }.not_to raise_error
end
it 'stores error messages' do
@@ -202,15 +178,93 @@ describe Gitlab::GithubImport::Importer, lib: true do
end
end
- let(:project) { create(:project, import_url: "#{repo_root}/octocat/Hello-World.git", wiki_access_level: ProjectFeature::DISABLED) }
+ shared_examples 'Gitlab::GithubImport unit-testing' do
+ describe '#clean_up_restored_branches' do
+ subject { described_class.new(project) }
+
+ before do
+ allow(gh_pull_request).to receive(:source_branch_exists?).at_least(:once) { false }
+ allow(gh_pull_request).to receive(:target_branch_exists?).at_least(:once) { false }
+ end
+
+ context 'when pull request stills open' do
+ let(:gh_pull_request) { Gitlab::GithubImport::PullRequestFormatter.new(project, pull_request) }
+
+ it 'does not remove branches' do
+ expect(subject).not_to receive(:remove_branch)
+ subject.send(:clean_up_restored_branches, gh_pull_request)
+ end
+ end
+
+ context 'when pull request is closed' do
+ let(:gh_pull_request) { Gitlab::GithubImport::PullRequestFormatter.new(project, closed_pull_request) }
+
+ it 'does remove branches' do
+ expect(subject).to receive(:remove_branch).at_least(2).times
+ subject.send(:clean_up_restored_branches, gh_pull_request)
+ end
+ end
+ end
+ end
+
+ let(:project) { create(:project, :wiki_disabled, import_url: "#{repo_root}/octocat/Hello-World.git") }
+ let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
let(:credentials) { { user: 'joe' } }
+ let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
+ let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
+ let(:repository) { double(id: 1, fork: false) }
+ let(:source_sha) { create(:commit, project: project).id }
+ let(:source_branch) { double(ref: 'branch-merged', repo: repository, sha: source_sha, user: octocat) }
+ let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
+ let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha, user: octocat) }
+ let(:pull_request) do
+ double(
+ number: 1347,
+ milestone: nil,
+ state: 'open',
+ title: 'New feature',
+ body: 'Please pull these awesome changes',
+ head: source_branch,
+ base: target_branch,
+ assignee: nil,
+ user: octocat,
+ created_at: created_at,
+ updated_at: updated_at,
+ closed_at: nil,
+ merged_at: nil,
+ url: "#{api_root}/repos/octocat/Hello-World/pulls/1347",
+ labels: [double(name: 'Label #2')]
+ )
+ end
+ let(:closed_pull_request) do
+ double(
+ number: 1347,
+ milestone: nil,
+ state: 'closed',
+ title: 'New feature',
+ body: 'Please pull these awesome changes',
+ head: source_branch,
+ base: target_branch,
+ assignee: nil,
+ user: octocat,
+ created_at: created_at,
+ updated_at: updated_at,
+ closed_at: updated_at,
+ merged_at: nil,
+ url: "#{api_root}/repos/octocat/Hello-World/pulls/1347",
+ labels: [double(name: 'Label #2')]
+ )
+ end
+
context 'when importing a GitHub project' do
let(:api_root) { 'https://api.github.com' }
let(:repo_root) { 'https://github.com' }
+ subject { described_class.new(project) }
it_behaves_like 'Gitlab::GithubImport::Importer#execute'
it_behaves_like 'Gitlab::GithubImport::Importer#execute an error occurs'
+ it_behaves_like 'Gitlab::GithubImport unit-testing'
describe '#client' do
it 'instantiates a Client' do
@@ -220,7 +274,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
{}
)
- described_class.new(project).client
+ subject.client
end
end
end
@@ -228,6 +282,8 @@ describe Gitlab::GithubImport::Importer, lib: true do
context 'when importing a Gitea project' do
let(:api_root) { 'https://try.gitea.io/api/v1' }
let(:repo_root) { 'https://try.gitea.io' }
+ subject { described_class.new(project) }
+
before do
project.update(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git")
end
@@ -236,6 +292,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
let(:expected_not_called) { [:import_releases] }
end
it_behaves_like 'Gitlab::GithubImport::Importer#execute an error occurs'
+ it_behaves_like 'Gitlab::GithubImport unit-testing'
describe '#client' do
it 'instantiates a Client' do
@@ -245,7 +302,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
{ host: "#{repo_root}:443/foo", api_version: 'v1' }
)
- described_class.new(project).client
+ subject.client
end
end
end
diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
index e31ed9c1fa0..f34d09f2c1d 100644
--- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
@@ -1,8 +1,9 @@
require 'spec_helper'
describe Gitlab::GithubImport::IssueFormatter, lib: true do
- let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
- let(:octocat) { double(id: 123456, login: 'octocat') }
+ let(:client) { double }
+ let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) }
+ let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
@@ -23,7 +24,11 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
}
end
- subject(:issue) { described_class.new(project, raw_data) }
+ subject(:issue) { described_class.new(project, raw_data, client) }
+
+ before do
+ allow(client).to receive(:user).and_return(octocat)
+ end
shared_examples 'Gitlab::GithubImport::IssueFormatter#attributes' do
context 'when issue is open' do
@@ -75,11 +80,17 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
expect(issue.attributes.fetch(:assignee_id)).to be_nil
end
- it 'returns GitLab user id as assignee_id when is a GitLab user' do
+ it 'returns GitLab user id associated with GitHub id as assignee_id' do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(issue.attributes.fetch(:assignee_id)).to eq gl_user.id
end
+
+ it 'returns GitLab user id associated with GitHub email as assignee_id' do
+ gl_user = create(:user, email: octocat.email)
+
+ expect(issue.attributes.fetch(:assignee_id)).to eq gl_user.id
+ end
end
context 'when it has a milestone' do
@@ -100,16 +111,22 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
context 'when author is a GitLab user' do
let(:raw_data) { double(base_data.merge(user: octocat)) }
- it 'returns project#creator_id as author_id when is not a GitLab user' do
+ it 'returns project creator_id as author_id when is not a GitLab user' do
expect(issue.attributes.fetch(:author_id)).to eq project.creator_id
end
- it 'returns GitLab user id as author_id when is a GitLab user' do
+ it 'returns GitLab user id associated with GitHub id as author_id' do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(issue.attributes.fetch(:author_id)).to eq gl_user.id
end
+ it 'returns GitLab user id associated with GitHub email as author_id' do
+ gl_user = create(:user, email: octocat.email)
+
+ expect(issue.attributes.fetch(:author_id)).to eq gl_user.id
+ end
+
it 'returns description without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb
index 8098754d735..565435824fd 100644
--- a/spec/lib/gitlab/github_import/label_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::LabelFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:raw) { double(name: 'improvements', color: 'e6e6e6') }
subject { described_class.new(project, raw) }
@@ -25,7 +25,7 @@ describe Gitlab::GithubImport::LabelFormatter, lib: true do
context 'when label exists' do
it 'does not create a new label' do
- project.labels.create(name: raw.name)
+ Labels::CreateService.new(name: raw.name).execute(project: project)
expect { subject.create! }.not_to change(Label, :count)
end
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index 2b3256edcb2..b7c59918a76 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -1,16 +1,22 @@
require 'spec_helper'
describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
- let(:project) { create(:project) }
+ let(:client) { double }
+ let(:project) { create(:project, :repository) }
let(:source_sha) { create(:commit, project: project).id }
- let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id }
+ let(:target_commit) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit) }
+ let(:target_sha) { target_commit.id }
+ let(:target_short_sha) { target_commit.id.to_s[0..7] }
let(:repository) { double(id: 1, fork: false) }
let(:source_repo) { repository }
- let(:source_branch) { double(ref: 'feature', repo: source_repo, sha: source_sha) }
+ let(:source_branch) { double(ref: 'branch-merged', repo: source_repo, sha: source_sha) }
+ let(:forked_source_repo) { double(id: 2, fork: true, name: 'otherproject', full_name: 'company/otherproject') }
let(:target_repo) { repository }
- let(:target_branch) { double(ref: 'master', repo: target_repo, sha: target_sha) }
- let(:removed_branch) { double(ref: 'removed-branch', repo: source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b') }
- let(:octocat) { double(id: 123456, login: 'octocat') }
+ let(:target_branch) { double(ref: 'master', repo: target_repo, sha: target_sha, user: octocat) }
+ let(:removed_branch) { double(ref: 'removed-branch', repo: source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) }
+ let(:forked_branch) { double(ref: 'master', repo: forked_source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) }
+ let(:branch_deleted_repo) { double(ref: 'master', repo: nil, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) }
+ let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') }
let(:base_data) do
@@ -32,7 +38,11 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
}
end
- subject(:pull_request) { described_class.new(project, raw_data) }
+ subject(:pull_request) { described_class.new(project, raw_data, client) }
+
+ before do
+ allow(client).to receive(:user).and_return(octocat)
+ end
shared_examples 'Gitlab::GithubImport::PullRequestFormatter#attributes' do
context 'when pull request is open' do
@@ -44,7 +54,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
title: 'New feature',
description: "*Created by: octocat*\n\nPlease pull these awesome changes",
source_project: project,
- source_branch: 'feature',
+ source_branch: 'branch-merged',
source_branch_sha: source_sha,
target_project: project,
target_branch: 'master',
@@ -54,7 +64,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
author_id: project.creator_id,
assignee_id: nil,
created_at: created_at,
- updated_at: updated_at
+ updated_at: updated_at,
+ imported: true
}
expect(pull_request.attributes).to eq(expected)
@@ -70,7 +81,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
title: 'New feature',
description: "*Created by: octocat*\n\nPlease pull these awesome changes",
source_project: project,
- source_branch: 'feature',
+ source_branch: 'branch-merged',
source_branch_sha: source_sha,
target_project: project,
target_branch: 'master',
@@ -80,7 +91,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
author_id: project.creator_id,
assignee_id: nil,
created_at: created_at,
- updated_at: updated_at
+ updated_at: updated_at,
+ imported: true
}
expect(pull_request.attributes).to eq(expected)
@@ -97,7 +109,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
title: 'New feature',
description: "*Created by: octocat*\n\nPlease pull these awesome changes",
source_project: project,
- source_branch: 'feature',
+ source_branch: 'branch-merged',
source_branch_sha: source_sha,
target_project: project,
target_branch: 'master',
@@ -107,7 +119,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
author_id: project.creator_id,
assignee_id: nil,
created_at: created_at,
- updated_at: updated_at
+ updated_at: updated_at,
+ imported: true
}
expect(pull_request.attributes).to eq(expected)
@@ -121,26 +134,38 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
expect(pull_request.attributes.fetch(:assignee_id)).to be_nil
end
- it 'returns GitLab user id as assignee_id when is a GitLab user' do
+ it 'returns GitLab user id associated with GitHub id as assignee_id' do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(pull_request.attributes.fetch(:assignee_id)).to eq gl_user.id
end
+
+ it 'returns GitLab user id associated with GitHub email as assignee_id' do
+ gl_user = create(:user, email: octocat.email)
+
+ expect(pull_request.attributes.fetch(:assignee_id)).to eq gl_user.id
+ end
end
context 'when author is a GitLab user' do
let(:raw_data) { double(base_data.merge(user: octocat)) }
- it 'returns project#creator_id as author_id when is not a GitLab user' do
+ it 'returns project creator_id as author_id when is not a GitLab user' do
expect(pull_request.attributes.fetch(:author_id)).to eq project.creator_id
end
- it 'returns GitLab user id as author_id when is a GitLab user' do
+ it 'returns GitLab user id associated with GitHub id as author_id' do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id
end
+ it 'returns GitLab user id associated with GitHub email as author_id' do
+ gl_user = create(:user, email: octocat.email)
+
+ expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id
+ end
+
it 'returns description without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
@@ -177,21 +202,37 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
let(:raw_data) { double(base_data) }
it 'returns branch ref' do
- expect(pull_request.source_branch_name).to eq 'feature'
+ expect(pull_request.source_branch_name).to eq 'branch-merged'
end
end
context 'when source branch does not exist' do
let(:raw_data) { double(base_data.merge(head: removed_branch)) }
- it 'prefixes branch name with pull request number' do
- expect(pull_request.source_branch_name).to eq 'pull/1347/removed-branch'
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/removed-branch"
+ end
+ end
+
+ context 'when source branch is from a fork' do
+ let(:raw_data) { double(base_data.merge(head: forked_branch)) }
+
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/master"
+ end
+ end
+
+ context 'when source branch is from a deleted fork' do
+ let(:raw_data) { double(base_data.merge(head: branch_deleted_repo)) }
+
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/master"
end
end
end
shared_examples 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name' do
- context 'when source branch exists' do
+ context 'when target branch exists' do
let(:raw_data) { double(base_data) }
it 'returns branch ref' do
@@ -202,8 +243,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
context 'when target branch does not exist' do
let(:raw_data) { double(base_data.merge(base: removed_branch)) }
- it 'prefixes branch name with pull request number' do
- expect(pull_request.target_branch_name).to eq 'pull/1347/removed-branch'
+ it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do
+ expect(pull_request.target_branch_name).to eq 'gl-2e5d3239/1347/octocat/removed-branch'
end
end
end
@@ -254,6 +295,40 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
end
end
+ describe '#cross_project?' do
+ context 'when source and target repositories are different' do
+ let(:raw_data) { double(base_data.merge(head: forked_branch)) }
+
+ it 'returns true' do
+ expect(pull_request.cross_project?).to eq true
+ end
+ end
+
+ context 'when source repository does not exist anymore' do
+ let(:raw_data) { double(base_data.merge(head: branch_deleted_repo)) }
+
+ it 'returns true' do
+ expect(pull_request.cross_project?).to eq true
+ end
+ end
+
+ context 'when source and target repositories are the same' do
+ let(:raw_data) { double(base_data.merge(head: source_branch)) }
+
+ it 'returns false' do
+ expect(pull_request.cross_project?).to eq false
+ end
+ end
+ end
+
+ describe '#source_branch_exists?' do
+ let(:raw_data) { double(base_data.merge(head: forked_branch)) }
+
+ it 'returns false when is a cross_project' do
+ expect(pull_request.source_branch_exists?).to eq false
+ end
+ end
+
describe '#url' do
let(:raw_data) { double(base_data) }
@@ -261,4 +336,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
expect(pull_request.url).to eq 'https://api.github.com/repos/octocat/Hello-World/pulls/1347'
end
end
+
+ describe '#opened?' do
+ let(:raw_data) { double(base_data.merge(state: 'open')) }
+
+ it 'returns true when state is "open"' do
+ expect(pull_request.opened?).to be_truthy
+ end
+ end
end
diff --git a/spec/lib/gitlab/github_import/release_formatter_spec.rb b/spec/lib/gitlab/github_import/release_formatter_spec.rb
index 793128c6ab9..13b15e669ab 100644
--- a/spec/lib/gitlab/github_import/release_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/release_formatter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::GithubImport::ReleaseFormatter, lib: true do
- let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
+ let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
diff --git a/spec/lib/gitlab/github_import/user_formatter_spec.rb b/spec/lib/gitlab/github_import/user_formatter_spec.rb
new file mode 100644
index 00000000000..db792233657
--- /dev/null
+++ b/spec/lib/gitlab/github_import/user_formatter_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe Gitlab::GithubImport::UserFormatter, lib: true do
+ let(:client) { double }
+ let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') }
+
+ subject(:user) { described_class.new(client, octocat) }
+
+ before do
+ allow(client).to receive(:user).and_return(octocat)
+ end
+
+ describe '#gitlab_id' do
+ context 'when GitHub user is a GitLab user' do
+ it 'return GitLab user id when user associated their account with GitHub' do
+ gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
+
+ expect(user.gitlab_id).to eq gl_user.id
+ end
+
+ it 'returns GitLab user id when user primary email matches GitHub email' do
+ gl_user = create(:user, email: octocat.email)
+
+ expect(user.gitlab_id).to eq gl_user.id
+ end
+
+ it 'returns GitLab user id when any of user linked emails matches GitHub email' do
+ gl_user = create(:user, email: 'johndoe@example.com')
+ create(:email, user: gl_user, email: octocat.email)
+
+ expect(user.gitlab_id).to eq gl_user.id
+ end
+ end
+
+ it 'returns nil when GitHub user is not a GitLab user' do
+ expect(user.gitlab_id).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 097861fd34d..ccaa88a5c79 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::GoogleCodeImport::Importer, lib: true do
'user_map' => { 'thilo...' => "@#{mapped_user.username}" }
}
end
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
subject { described_class.new(project) }
diff --git a/spec/lib/gitlab/graphs/commits_spec.rb b/spec/lib/gitlab/graphs/commits_spec.rb
index f5c064303ad..abb5a26060f 100644
--- a/spec/lib/gitlab/graphs/commits_spec.rb
+++ b/spec/lib/gitlab/graphs/commits_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Graphs::Commits, lib: true do
- let!(:project) { create(:project, :public, :empty_repo) }
+ let!(:project) { create(:empty_project, :public) }
let!(:commit1) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: Time.now) }
let!(:commit1_yesterday) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: 1.day.ago)}
diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb
index fc021416d92..e49799ad105 100644
--- a/spec/lib/gitlab/highlight_spec.rb
+++ b/spec/lib/gitlab/highlight_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Highlight, lib: true do
include RepoHelpers
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:commit) { project.commit(sample_commit.id) }
@@ -12,10 +12,10 @@ describe Gitlab::Highlight, lib: true do
Gitlab::Highlight.highlight_lines(project.repository, commit.id, 'files/ruby/popen.rb')
end
- it 'should properly highlight all the lines' do
- expect(lines[4]).to eq(%Q{<span id="LC5" class="line"> <span class="kp">extend</span> <span class="nb">self</span></span>\n})
- expect(lines[21]).to eq(%Q{<span id="LC22" class="line"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>\n})
- expect(lines[26]).to eq(%Q{<span id="LC27" class="line"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>\n})
+ it 'highlights all the lines properly' do
+ expect(lines[4]).to eq(%Q{<span id="LC5" class="line" lang="ruby"> <span class="kp">extend</span> <span class="nb">self</span></span>\n})
+ expect(lines[21]).to eq(%Q{<span id="LC22" class="line" lang="ruby"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>\n})
+ expect(lines[26]).to eq(%Q{<span id="LC27" class="line" lang="ruby"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>\n})
end
describe 'with CRLF' do
@@ -26,7 +26,7 @@ describe Gitlab::Highlight, lib: true do
end
it 'strips extra LFs' do
- expect(lines[0]).to eq("<span id=\"LC1\" class=\"line\">test </span>")
+ expect(lines[0]).to eq("<span id=\"LC1\" class=\"line\" lang=\"plaintext\">test </span>")
end
end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 7fb6829f582..002cffd3062 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -29,6 +29,7 @@ notes:
- resolved_by
- todos
- events
+- system_note_metadata
label_links:
- target
- label
@@ -52,6 +53,7 @@ snippets:
- project
- notes
- award_emoji
+- user_agent_detail
releases:
- project
project_members:
@@ -96,6 +98,7 @@ variables:
triggers:
- project
- trigger_requests
+- owner
deploy_keys:
- user
- deploy_keys_projects
@@ -128,12 +131,12 @@ project:
- campfire_service
- drone_ci_service
- emails_on_push_service
-- builds_email_service
- pipelines_email_service
- mattermost_slash_commands_service
- slack_slash_commands_service
- irker_service
- pivotaltracker_service
+- prometheus_service
- hipchat_service
- flowdock_service
- assembla_service
@@ -152,6 +155,7 @@ project:
- gitlab_issue_tracker_service
- external_wiki_service
- kubernetes_service
+- mock_ci_service
- forked_project_link
- forked_from_project
- forked_project_links
@@ -191,15 +195,18 @@ project:
- environments
- deployments
- project_feature
+- pages_domains
- authorized_users
- project_authorizations
- route
- statistics
+- uploads
award_emoji:
- awardable
- user
priorities:
- label
timelogs:
-- trackable
+- issue
+- merge_request
- user
diff --git a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
index ea65a5dfed1..e24d070706a 100644
--- a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb
@@ -17,7 +17,7 @@ describe 'Import/Export attribute configuration', lib: true do
# Remove duplicated or add missing models
# - project is not part of the tree, so it has to be added manually.
# - milestone, labels have both singular and plural versions in the tree, so remove the duplicates.
- names.flatten.uniq - ['milestones', 'labels'] + ['project']
+ names.flatten.uniq - %w(milestones labels) + ['project']
end
let(:safe_attributes_file) { 'spec/lib/gitlab/import_export/safe_model_attributes.yml' }
diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
index d6ee94442cb..579a31ead58 100644
--- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::AvatarSaver, lib: true do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
- let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:project_with_avatar) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let(:project) { create(:empty_project) }
diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb
index a88ddd17aca..b88b9c18c15 100644
--- a/spec/lib/gitlab/import_export/file_importer_spec.rb
+++ b/spec/lib/gitlab/import_export/file_importer_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::FileImporter, lib: true do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') }
- let(:export_path) { "#{Dir::tmpdir}/file_importer_spec" }
+ let(:export_path) { "#{Dir.tmpdir}/file_importer_spec" }
let(:valid_file) { "#{shared.export_path}/valid.json" }
let(:symlink_file) { "#{shared.export_path}/invalid.json" }
let(:subfolder_symlink_file) { "#{shared.export_path}/subfolder/invalid.json" }
diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb
index d6409a29550..f3fd0d82875 100644
--- a/spec/lib/gitlab/import_export/import_export_spec.rb
+++ b/spec/lib/gitlab/import_export/import_export_spec.rb
@@ -2,14 +2,15 @@ require 'spec_helper'
describe Gitlab::ImportExport, services: true do
describe 'export filename' do
- let(:project) { create(:project, :public, path: 'project-path') }
+ let(:group) { create(:group, :nested) }
+ let(:project) { create(:empty_project, :public, path: 'project-path', namespace: group) }
it 'contains the project path' do
expect(described_class.export_filename(project: project)).to include(project.path)
end
it 'contains the namespace path' do
- expect(described_class.export_filename(project: project)).to include(project.namespace.path)
+ expect(described_class.export_filename(project: project)).to include(project.namespace.full_path.tr('/', '_'))
end
it 'does not go over a certain length' do
diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb
index b069696b5c7..b9d4e59e770 100644
--- a/spec/lib/gitlab/import_export/members_mapper_spec.rb
+++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::ImportExport::MembersMapper, services: true do
describe 'map members' do
let(:user) { create(:admin, authorized_projects_populated: true) }
- let(:project) { create(:project, :public, name: 'searchable_project') }
+ let(:project) { create(:empty_project, :public, name: 'searchable_project') }
let(:user2) { create(:user, authorized_projects_populated: true) }
let(:exported_user_id) { 99 }
let(:exported_members) do
@@ -92,5 +92,51 @@ describe Gitlab::ImportExport::MembersMapper, services: true do
expect(members_mapper.map[exported_user_id]).to eq(user2.id)
end
end
+
+ context 'importer same as group member' do
+ let(:user2) { create(:admin, authorized_projects_populated: true) }
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, :public, name: 'searchable_project', namespace: group) }
+ let(:members_mapper) do
+ described_class.new(
+ exported_members: exported_members, user: user2, project: project)
+ end
+
+ before do
+ group.add_users([user, user2], GroupMember::DEVELOPER)
+ end
+
+ it 'maps the project member' do
+ expect(members_mapper.map[exported_user_id]).to eq(user2.id)
+ end
+
+ it 'maps the project member if it already exists' do
+ project.add_master(user2)
+
+ expect(members_mapper.map[exported_user_id]).to eq(user2.id)
+ end
+ end
+
+ context 'importing group members' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, namespace: group) }
+ let(:members_mapper) do
+ described_class.new(
+ exported_members: exported_members, user: user, project: project)
+ end
+
+ before do
+ group.add_users([user, user2], GroupMember::DEVELOPER)
+ user.update(email: 'invite@test.com')
+ end
+
+ it 'maps the importer' do
+ expect(members_mapper.map[-1]).to eq(user.id)
+ end
+
+ it 'maps the group member' do
+ expect(members_mapper.map[exported_user_id]).to eq(user2.id)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/import_export/model_configuration_spec.rb b/spec/lib/gitlab/import_export/model_configuration_spec.rb
index 9b492d1b9c7..2ede5cdd2ad 100644
--- a/spec/lib/gitlab/import_export/model_configuration_spec.rb
+++ b/spec/lib/gitlab/import_export/model_configuration_spec.rb
@@ -14,7 +14,7 @@ describe 'Import/Export model configuration', lib: true do
# - project is not part of the tree, so it has to be added manually.
# - milestone, labels have both singular and plural versions in the tree, so remove the duplicates.
# - User, Author... Models we do not care about for checking models
- names.flatten.uniq - ['milestones', 'labels', 'user', 'author'] + ['project']
+ names.flatten.uniq - %w(milestones labels user author) + ['project']
end
let(:all_models_yml) { 'spec/lib/gitlab/import_export/all_models.yml' }
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 2c0750c3377..d9b67426818 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2539,7 +2539,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": true,
+ "merge_when_pipeline_succeeds": true,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -2976,7 +2976,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -3260,7 +3260,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -3544,7 +3544,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -4234,7 +4234,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -4782,7 +4782,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -5281,7 +5281,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -5541,7 +5541,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -6231,7 +6231,7 @@
"merge_params": {
"force_remove_source_branch": null
},
- "merge_when_build_succeeds": false,
+ "merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
"deleted_at": null,
@@ -6507,7 +6507,6 @@
"tag": null,
"yaml_errors": null,
"committed_at": null,
- "gl_project_id": 5,
"status": "failed",
"started_at": null,
"finished_at": null,
@@ -6565,7 +6564,6 @@
"artifacts_file": {
"url": null
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": null
},
@@ -6603,7 +6601,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz"
},
@@ -6624,7 +6621,6 @@
"tag": null,
"yaml_errors": null,
"committed_at": null,
- "gl_project_id": 5,
"status": "failed",
"started_at": null,
"finished_at": null,
@@ -6659,7 +6655,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz"
},
@@ -6695,7 +6690,6 @@
"artifacts_file": {
"url": null
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": null
},
@@ -6716,7 +6710,6 @@
"tag": null,
"yaml_errors": null,
"committed_at": null,
- "gl_project_id": 5,
"status": "failed",
"started_at": null,
"finished_at": null,
@@ -6751,7 +6744,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz"
},
@@ -6787,7 +6779,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz"
},
@@ -6808,7 +6799,6 @@
"tag": null,
"yaml_errors": null,
"committed_at": null,
- "gl_project_id": 5,
"status": "failed",
"started_at": null,
"finished_at": null,
@@ -6843,7 +6833,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz"
},
@@ -6879,7 +6868,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz"
},
@@ -6900,7 +6888,6 @@
"tag": null,
"yaml_errors": null,
"committed_at": null,
- "gl_project_id": 5,
"status": "failed",
"started_at": null,
"finished_at": null,
@@ -6935,7 +6922,6 @@
"artifacts_file": {
"url": null
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": null
},
@@ -6971,7 +6957,6 @@
"artifacts_file": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip"
},
- "gl_project_id": 5,
"artifacts_metadata": {
"url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz"
},
@@ -6981,11 +6966,15 @@
]
}
],
- "variables": [
-
- ],
"triggers": [
-
+ {
+ "id": 123,
+ "token": "cdbfasdf44a5958c83654733449e585",
+ "project_id": 5,
+ "deleted_at": null,
+ "created_at": "2017-01-16T15:25:28.637Z",
+ "updated_at": "2017-01-16T15:25:28.637Z"
+ }
],
"deploy_keys": [
@@ -7042,7 +7031,7 @@
"updated_at": "2016-06-14T15:01:51.303Z",
"active": false,
"properties": {
- "notify_only_broken_builds": true
+ "notify_only_broken_pipelines": true
},
"template": false,
"push_events": true,
@@ -7050,7 +7039,7 @@
"merge_requests_events": true,
"tag_push_events": true,
"note_events": true,
- "build_events": true,
+ "pipeline_events": true,
"category": "common",
"default": false,
"wiki_page_events": true
@@ -7169,7 +7158,7 @@
"updated_at": "2016-06-14T15:01:51.219Z",
"active": false,
"properties": {
- "notify_only_broken_builds": true
+ "notify_only_broken_pipelines": true
},
"template": false,
"push_events": true,
@@ -7177,7 +7166,7 @@
"merge_requests_events": true,
"tag_push_events": true,
"note_events": true,
- "build_events": true,
+ "pipeline_events": true,
"category": "common",
"default": false,
"wiki_page_events": true
@@ -7330,27 +7319,6 @@
"wiki_page_events": true
},
{
- "id": 85,
- "title": "Builds emails",
- "project_id": 5,
- "created_at": "2016-06-14T15:01:51.090Z",
- "updated_at": "2016-06-14T15:01:51.090Z",
- "active": false,
- "properties": {
- "notify_only_broken_builds": true
- },
- "template": false,
- "push_events": true,
- "issues_events": true,
- "merge_requests_events": true,
- "tag_push_events": true,
- "note_events": true,
- "build_events": true,
- "category": "common",
- "default": false,
- "wiki_page_events": true
- },
- {
"id": 84,
"title": "Buildkite",
"project_id": 5,
@@ -7498,4 +7466,4 @@
"updated_at": "2016-09-23T11:58:28.000Z",
"wiki_access_level": 20
}
-} \ No newline at end of file
+}
diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json
new file mode 100644
index 00000000000..a78836c3c34
--- /dev/null
+++ b/spec/lib/gitlab/import_export/project.light.json
@@ -0,0 +1,48 @@
+{
+ "description": "Nisi et repellendus ut enim quo accusamus vel magnam.",
+ "visibility_level": 10,
+ "archived": false,
+ "labels": [
+ {
+ "id": 2,
+ "title": "test2",
+ "color": "#428bca",
+ "project_id": 8,
+ "created_at": "2016-07-22T08:55:44.161Z",
+ "updated_at": "2016-07-22T08:55:44.161Z",
+ "template": false,
+ "description": "",
+ "type": "ProjectLabel",
+ "priorities": [
+ ]
+ },
+ {
+ "id": 3,
+ "title": "test3",
+ "color": "#428bca",
+ "group_id": 8,
+ "created_at": "2016-07-22T08:55:44.161Z",
+ "updated_at": "2016-07-22T08:55:44.161Z",
+ "template": false,
+ "description": "",
+ "project_id": null,
+ "type": "GroupLabel",
+ "priorities": [
+ {
+ "id": 1,
+ "project_id": 5,
+ "label_id": 1,
+ "priority": 1,
+ "created_at": "2016-10-18T09:35:43.338Z",
+ "updated_at": "2016-10-18T09:35:43.338Z"
+ }
+ ]
+ }
+ ],
+ "snippets": [
+
+ ],
+ "hooks": [
+
+ ]
+} \ No newline at end of file
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 4b07fa53bf5..c36f12dbd82 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -3,24 +3,24 @@ include ImportExport::CommonUtil
describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
describe 'restore project tree' do
- let(:user) { create(:user) }
- let(:namespace) { create(:namespace, owner: user) }
- let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') }
- let!(:project) { create(:empty_project, name: 'project', path: 'project', builds_access_level: ProjectFeature::DISABLED, issues_access_level: ProjectFeature::DISABLED) }
- let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) }
- let(:restored_project_json) { project_tree_restorer.restore }
+ before(:context) do
+ @user = create(:user)
- before do
- allow(shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
+ RSpec::Mocks.with_temporary_scope do
+ @shared = Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path')
+ allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
+ @project = create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project')
+ project_tree_restorer = described_class.new(user: @user, shared: @shared, project: @project)
+ @restored_project_json = project_tree_restorer.restore
+ end
end
context 'JSON' do
it 'restores models based on JSON' do
- expect(restored_project_json).to be true
+ expect(@restored_project_json).to be true
end
it 'restore correct project features' do
- restored_project_json
project = Project.find_by_path('project')
expect(project.project_feature.issues_access_level).to eq(ProjectFeature::DISABLED)
@@ -31,62 +31,42 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
end
it 'has the same label associated to two issues' do
- restored_project_json
-
expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2)
end
it 'has milestones associated to two separate issues' do
- restored_project_json
-
expect(Milestone.find_by_description('test milestone').issues.count).to eq(2)
end
it 'creates a valid pipeline note' do
- restored_project_json
-
expect(Ci::Pipeline.first.notes).not_to be_empty
end
it 'restores pipelines with missing ref' do
- restored_project_json
-
expect(Ci::Pipeline.where(ref: nil)).not_to be_empty
end
it 'restores the correct event with symbolised data' do
- restored_project_json
-
expect(Event.where.not(data: nil).first.data[:ref]).not_to be_empty
end
it 'preserves updated_at on issues' do
- restored_project_json
-
issue = Issue.where(description: 'Aliquam enim illo et possimus.').first
expect(issue.reload.updated_at.to_s).to eq('2016-06-14 15:02:47 UTC')
end
it 'contains the merge access levels on a protected branch' do
- restored_project_json
-
expect(ProtectedBranch.first.merge_access_levels).not_to be_empty
end
it 'contains the push access levels on a protected branch' do
- restored_project_json
-
expect(ProtectedBranch.first.push_access_levels).not_to be_empty
end
context 'event at forth level of the tree' do
let(:event) { Event.where(title: 'test levels').first }
- before do
- restored_project_json
- end
-
it 'restores the event' do
expect(event).not_to be_nil
end
@@ -99,77 +79,40 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
it 'has the correct data for merge request st_diffs' do
# makes sure we are renaming the custom method +utf8_st_diffs+ into +st_diffs+
- expect { restored_project_json }.to change(MergeRequestDiff.where.not(st_diffs: nil), :count).by(9)
+ expect(MergeRequestDiff.where.not(st_diffs: nil).count).to eq(9)
end
it 'has labels associated to label links, associated to issues' do
- restored_project_json
-
expect(Label.first.label_links.first.target).not_to be_nil
end
it 'has project labels' do
- restored_project_json
-
expect(ProjectLabel.count).to eq(2)
end
it 'has no group labels' do
- restored_project_json
-
expect(GroupLabel.count).to eq(0)
end
- context 'with group' do
- let!(:project) do
- create(:empty_project,
- name: 'project',
- path: 'project',
- builds_access_level: ProjectFeature::DISABLED,
- issues_access_level: ProjectFeature::DISABLED,
- group: create(:group))
- end
-
- it 'has group labels' do
- restored_project_json
-
- expect(GroupLabel.count).to eq(1)
- end
-
- it 'has label priorities' do
- restored_project_json
-
- expect(GroupLabel.first.priorities).not_to be_empty
- end
- end
-
it 'has a project feature' do
- restored_project_json
-
- expect(project.project_feature).not_to be_nil
+ expect(@project.project_feature).not_to be_nil
end
it 'restores the correct service' do
- restored_project_json
-
expect(CustomIssueTrackerService.first).not_to be_nil
end
context 'Merge requests' do
- before do
- restored_project_json
- end
-
it 'always has the new project as a target' do
- expect(MergeRequest.find_by_title('MR1').target_project).to eq(project)
+ expect(MergeRequest.find_by_title('MR1').target_project).to eq(@project)
end
it 'has the same source project as originally if source/target are the same' do
- expect(MergeRequest.find_by_title('MR1').source_project).to eq(project)
+ expect(MergeRequest.find_by_title('MR1').source_project).to eq(@project)
end
it 'has the new project as target if source/target differ' do
- expect(MergeRequest.find_by_title('MR2').target_project).to eq(project)
+ expect(MergeRequest.find_by_title('MR2').target_project).to eq(@project)
end
it 'has no source if source/target differ' do
@@ -177,26 +120,91 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
end
end
- context 'project.json file access check' do
- it 'does not read a symlink' do
- Dir.mktmpdir do |tmpdir|
- setup_symlink(tmpdir, 'project.json')
- allow(shared).to receive(:export_path).and_call_original
+ context 'tokens are regenerated' do
+ it 'has a new CI trigger token' do
+ expect(Ci::Trigger.where(token: 'cdbfasdf44a5958c83654733449e585')).to be_empty
+ end
+
+ it 'has a new CI build token' do
+ expect(Ci::Build.where(token: 'abcd')).to be_empty
+ end
+ end
+
+ context 'has restored the correct number of records' do
+ it 'has the correct number of merge requests' do
+ expect(@project.merge_requests.size).to eq(9)
+ end
+
+ it 'has the correct number of triggers' do
+ expect(@project.triggers.size).to eq(1)
+ end
- restored_project_json
+ it 'has the correct number of pipelines and statuses' do
+ expect(@project.pipelines.size).to eq(5)
- expect(shared.errors.first).not_to include('test')
- end
+ @project.pipelines.zip([2, 2, 2, 2, 2])
+ .each do |(pipeline, expected_status_size)|
+ expect(pipeline.statuses.size).to eq(expected_status_size)
+ end
end
end
+ end
+ end
+
+ context 'Light JSON' do
+ let(:user) { create(:user) }
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') }
+ let!(:project) { create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') }
+ let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) }
+ let(:restored_project_json) { project_tree_restorer.restore }
+
+ before do
+ allow(ImportExport).to receive(:project_filename).and_return('project.light.json')
+ allow(shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/')
+ end
- context 'when there is an existing build with build token' do
- it 'restores project json correctly' do
- create(:ci_build, token: 'abcd')
+ context 'project.json file access check' do
+ it 'does not read a symlink' do
+ Dir.mktmpdir do |tmpdir|
+ setup_symlink(tmpdir, 'project.json')
+ allow(shared).to receive(:export_path).and_call_original
- expect(restored_project_json).to be true
+ restored_project_json
+
+ expect(shared.errors.first).not_to include('test')
end
end
end
+
+ context 'when there is an existing build with build token' do
+ it 'restores project json correctly' do
+ create(:ci_build, token: 'abcd')
+
+ expect(restored_project_json).to be true
+ end
+ end
+
+ context 'with group' do
+ let!(:project) do
+ create(:empty_project,
+ :builds_disabled,
+ :issues_disabled,
+ name: 'project',
+ path: 'project',
+ group: create(:group))
+ end
+
+ before do
+ restored_project_json
+ end
+
+ it 'has group labels' do
+ expect(GroupLabel.count).to eq(1)
+ end
+
+ it 'has label priorities' do
+ expect(GroupLabel.first.priorities).not_to be_empty
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index c8bba553558..012c22ec5ad 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
describe 'saves the project tree into a json object' do
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
- let(:project_tree_saver) { described_class.new(project: project, shared: shared) }
- let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
+ let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:user) { create(:user) }
let(:project) { setup_project }
@@ -92,7 +92,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
end
it 'has pipeline builds' do
- expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build'}).to eq(1)
+ expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build' }).to eq(1)
end
it 'has pipeline commits' do
@@ -112,13 +112,13 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
end
it 'has project and group labels' do
- label_types = saved_project_json['issues'].first['label_links'].map { |link| link['label']['type']}
+ label_types = saved_project_json['issues'].first['label_links'].map { |link| link['label']['type'] }
- expect(label_types).to match_array(['ProjectLabel', 'GroupLabel'])
+ expect(label_types).to match_array(%w(ProjectLabel GroupLabel))
end
it 'has priorities associated to labels' do
- priorities = saved_project_json['issues'].first['label_links'].map { |link| link['label']['priorities']}
+ priorities = saved_project_json['issues'].first['label_links'].map { |link| link['label']['priorities'] }
expect(priorities.flatten).not_to be_empty
end
@@ -140,6 +140,51 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
expect(project_tree_saver.save).to be true
end
+
+ context 'group members' do
+ let(:user2) { create(:user, email: 'group@member.com') }
+ let(:member_emails) do
+ saved_project_json['project_members'].map do |pm|
+ pm['user']['email']
+ end
+ end
+
+ before do
+ Group.first.add_developer(user2)
+ end
+
+ it 'does not export group members if it has no permission' do
+ Group.first.add_developer(user)
+
+ expect(member_emails).not_to include('group@member.com')
+ end
+
+ it 'does not export group members as master' do
+ Group.first.add_master(user)
+
+ expect(member_emails).not_to include('group@member.com')
+ end
+
+ it 'exports group members as group owner' do
+ Group.first.add_owner(user)
+
+ expect(member_emails).to include('group@member.com')
+ end
+
+ context 'as admin' do
+ let(:user) { create(:admin) }
+
+ it 'exports group members as admin' do
+ expect(member_emails).to include('group@member.com')
+ end
+
+ it 'exports group members as project members' do
+ member_types = saved_project_json['project_members'].map { |pm| pm['source_type'] }
+
+ expect(member_types).to all(eq('Project'))
+ end
+ end
+ end
end
end
@@ -151,6 +196,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
project = create(:project,
:public,
+ :repository,
+ :issues_disabled,
+ :wiki_enabled,
+ :builds_private,
issues: [issue],
snippets: [snippet],
releases: [release],
@@ -166,10 +215,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
commit_status = create(:commit_status, project: project)
ci_pipeline = create(:ci_pipeline,
- project: project,
- sha: merge_request.diff_head_sha,
- ref: merge_request.source_branch,
- statuses: [commit_status])
+ project: project,
+ sha: merge_request.diff_head_sha,
+ ref: merge_request.source_branch,
+ statuses: [commit_status])
create(:ci_build, pipeline: ci_pipeline, project: project)
create(:milestone, project: project)
@@ -181,13 +230,9 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
project: project,
commit_id: ci_pipeline.sha)
- create(:event, target: milestone, project: project, action: Event::CREATED, author: user)
+ create(:event, :created, target: milestone, project: project, author: user)
create(:service, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker')
- project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
- project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::ENABLED)
- project.project_feature.update_attribute(:builds_access_level, ProjectFeature::PRIVATE)
-
project
end
diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb
index 3ceb1e7e803..48d74b07e27 100644
--- a/spec/lib/gitlab/import_export/reader_spec.rb
+++ b/spec/lib/gitlab/import_export/reader_spec.rb
@@ -86,6 +86,10 @@ describe Gitlab::ImportExport::Reader, lib: true do
expect(described_class.new(shared: shared).project_tree).to match(include: [{ issues: { methods: [:name] } }])
end
+ it 'generates the correct hash for group members' do
+ expect(described_class.new(shared: shared).group_members_tree).to match({ include: { user: { only: [:email] } } })
+ end
+
def setup_yaml(hash)
allow(YAML).to receive(:load_file).with(test_config).and_return(hash)
end
diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb
index db0084d6823..57e412b0cef 100644
--- a/spec/lib/gitlab/import_export/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb
@@ -55,8 +55,8 @@ describe Gitlab::ImportExport::RelationFactory, lib: true do
expect(created_object.project_id).to eq(project.id)
end
- it 'has a token' do
- expect(created_object.token).to eq(token)
+ it 'has a nil token' do
+ expect(created_object.token).to eq(nil)
end
context 'original service exists' do
@@ -178,4 +178,15 @@ describe Gitlab::ImportExport::RelationFactory, lib: true do
expect(created_object.author).to eq(new_user)
end
end
+
+ context 'encrypted attributes' do
+ let(:relation_sym) { 'Ci::Variable' }
+ let(:relation_hash) do
+ create(:ci_variable).as_json
+ end
+
+ it 'has no value for the encrypted attribute' do
+ expect(created_object.value).to be_nil
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/repo_bundler_spec.rb b/spec/lib/gitlab/import_export/repo_bundler_spec.rb
index 135e99bc953..a7f4e11271e 100644
--- a/spec/lib/gitlab/import_export/repo_bundler_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_bundler_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe Gitlab::ImportExport::RepoSaver, services: true do
describe 'bundle a project Git repo' do
let(:user) { create(:user) }
- let!(:project) { create(:project, :public, name: 'searchable_project') }
- let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
+ let!(:project) { create(:empty_project, :public, name: 'searchable_project') }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
let(:bundler) { described_class.new(project: project, shared: shared) }
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
new file mode 100644
index 00000000000..168a59e5139
--- /dev/null
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::RepoRestorer, services: true do
+ describe 'bundle a project Git repo' do
+ let(:user) { create(:user) }
+ let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') }
+ let!(:project) { create(:empty_project) }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
+ let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) }
+ let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) }
+ let(:restorer) do
+ described_class.new(path_to_bundle: bundle_path,
+ shared: shared,
+ project: project)
+ end
+
+ before do
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+
+ bundler.save
+ end
+
+ after do
+ FileUtils.rm_rf(export_path)
+ FileUtils.rm_rf(project_with_repo.repository.path_to_repo)
+ FileUtils.rm_rf(project.repository.path_to_repo)
+ end
+
+ it 'restores the repo successfully' do
+ expect(restorer.restore).to be true
+ end
+
+ it 'has the webhooks' do
+ restorer.restore
+
+ expect(Gitlab::Git::Hook.new('post-receive', project.repository.path_to_repo)).to exist
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 493bc2db21a..1ad16a9b57d 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -15,12 +15,14 @@ Issue:
- updated_by_id
- confidential
- deleted_at
+- closed_at
- due_date
- moved_to_id
- lock_version
- milestone_id
- weight
- time_estimate
+- relative_position
Event:
- id
- target_type
@@ -142,7 +144,7 @@ MergeRequest:
- updated_by_id
- merge_error
- merge_params
-- merge_when_build_succeeds
+- merge_when_pipeline_succeeds
- merge_user_id
- merge_commit_sha
- deleted_at
@@ -175,7 +177,6 @@ Ci::Pipeline:
- tag
- yaml_errors
- committed_at
-- gl_project_id
- status
- started_at
- finished_at
@@ -210,7 +211,6 @@ CommitStatus:
- target_url
- description
- artifacts_file
-- gl_project_id
- artifacts_metadata
- erased_by_id
- erased_at
@@ -222,6 +222,7 @@ CommitStatus:
- queued_at
- token
- lock_version
+- coverage_regex
Ci::Variable:
- id
- project_id
@@ -230,7 +231,6 @@ Ci::Variable:
- encrypted_value
- encrypted_value_salt
- encrypted_value_iv
-- gl_project_id
Ci::Trigger:
- id
- token
@@ -238,7 +238,8 @@ Ci::Trigger:
- deleted_at
- created_at
- updated_at
-- gl_project_id
+- owner_id
+- description
DeployKey:
- id
- user_id
@@ -349,8 +350,8 @@ LabelPriority:
Timelog:
- id
- time_spent
-- trackable_id
-- trackable_type
+- merge_request_id
+- issue_id
- user_id
- created_at
- updated_at
diff --git a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
index b628da0f3e8..071e5fac3f0 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe Gitlab::ImportExport::WikiRepoSaver, services: true do
describe 'bundle a wiki Git repo' do
let(:user) { create(:user) }
- let!(:project) { create(:project, :public, name: 'searchable_project') }
- let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" }
+ let!(:project) { create(:empty_project, :public, name: 'searchable_project') }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
let(:wiki_bundler) { described_class.new(project: project, shared: shared) }
let!(:project_wiki) { ProjectWiki.new(project, user) }
diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb
index 8cea38e9ff8..b3b5e5e7e33 100644
--- a/spec/lib/gitlab/import_sources_spec.rb
+++ b/spec/lib/gitlab/import_sources_spec.rb
@@ -22,16 +22,16 @@ describe Gitlab::ImportSources do
describe '.values' do
it 'returns an array' do
expected =
- [
- 'github',
- 'bitbucket',
- 'gitlab',
- 'google_code',
- 'fogbugz',
- 'git',
- 'gitlab_project',
- 'gitea'
- ]
+ %w(
+ github
+ bitbucket
+ gitlab
+ google_code
+ fogbugz
+ git
+ gitlab_project
+ gitea
+ )
expect(described_class.values).to eq(expected)
end
@@ -40,15 +40,15 @@ describe Gitlab::ImportSources do
describe '.importer_names' do
it 'returns an array of importer names' do
expected =
- [
- 'github',
- 'bitbucket',
- 'gitlab',
- 'google_code',
- 'fogbugz',
- 'gitlab_project',
- 'gitea'
- ]
+ %w(
+ github
+ bitbucket
+ gitlab
+ google_code
+ fogbugz
+ gitlab_project
+ gitea
+ )
expect(described_class.importer_names).to eq(expected)
end
diff --git a/spec/lib/gitlab/incoming_email_spec.rb b/spec/lib/gitlab/incoming_email_spec.rb
index 1dcf2c0668b..698bd72d0f8 100644
--- a/spec/lib/gitlab/incoming_email_spec.rb
+++ b/spec/lib/gitlab/incoming_email_spec.rb
@@ -23,6 +23,48 @@ describe Gitlab::IncomingEmail, lib: true do
end
end
+ describe 'self.supports_wildcard?' do
+ context 'address contains the wildard placeholder' do
+ before do
+ stub_incoming_email_setting(address: 'replies+%{key}@example.com')
+ end
+
+ it 'confirms that wildcard is supported' do
+ expect(described_class.supports_wildcard?).to be_truthy
+ end
+ end
+
+ context "address doesn't contain the wildcard placeholder" do
+ before do
+ stub_incoming_email_setting(address: 'replies@example.com')
+ end
+
+ it 'returns that wildcard is not supported' do
+ expect(described_class.supports_wildcard?).to be_falsey
+ end
+ end
+
+ context 'address is not set' do
+ before do
+ stub_incoming_email_setting(address: nil)
+ end
+
+ it 'returns that wildard is not supported' do
+ expect(described_class.supports_wildcard?).to be_falsey
+ end
+ end
+ end
+
+ context 'self.unsubscribe_address' do
+ before do
+ stub_incoming_email_setting(address: 'replies+%{key}@example.com')
+ end
+
+ it 'returns the address with interpolated reply key and unsubscribe suffix' do
+ expect(described_class.unsubscribe_address('key')).to eq('replies+key+unsubscribe@example.com')
+ end
+ end
+
context "self.reply_address" do
before do
stub_incoming_email_setting(address: "replies+%{key}@example.com")
@@ -48,4 +90,19 @@ describe Gitlab::IncomingEmail, lib: true do
expect(described_class.key_from_fallback_message_id('reply-key@localhost')).to eq('key')
end
end
+
+ context 'self.scan_fallback_references' do
+ let(:references) do
+ '<issue_1@localhost>' +
+ ' <reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost>' +
+ ',<exchange@microsoft.com>'
+ end
+
+ it 'returns reply key' do
+ expect(described_class.scan_fallback_references(references))
+ .to eq(%w[issue_1@localhost
+ reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost
+ exchange@microsoft.com])
+ end
+ end
end
diff --git a/spec/lib/gitlab/job_waiter_spec.rb b/spec/lib/gitlab/job_waiter_spec.rb
new file mode 100644
index 00000000000..780f5b1f8d7
--- /dev/null
+++ b/spec/lib/gitlab/job_waiter_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe Gitlab::JobWaiter do
+ describe '#wait' do
+ let(:waiter) { described_class.new(%w(a)) }
+ it 'returns when all jobs have been completed' do
+ expect(Gitlab::SidekiqStatus).to receive(:all_completed?).with(%w(a)).
+ and_return(true)
+
+ expect(waiter).not_to receive(:sleep)
+
+ waiter.wait
+ end
+
+ it 'sleeps between checking the job statuses' do
+ expect(Gitlab::SidekiqStatus).to receive(:all_completed?).
+ with(%w(a)).
+ and_return(false, true)
+
+ expect(waiter).to receive(:sleep).with(described_class::INTERVAL)
+
+ waiter.wait
+ end
+
+ it 'returns when timing out' do
+ expect(waiter).not_to receive(:sleep)
+ waiter.wait(0)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb
index c9bd52a3b8f..91f9d06b85a 100644
--- a/spec/lib/gitlab/kubernetes_spec.rb
+++ b/spec/lib/gitlab/kubernetes_spec.rb
@@ -9,7 +9,7 @@ describe Gitlab::Kubernetes do
let(:pod_name) { 'pod1' }
let(:container_name) { 'container1' }
- subject(:result) { URI::parse(container_exec_url(api_url, namespace, pod_name, container_name)) }
+ subject(:result) { URI.parse(container_exec_url(api_url, namespace, pod_name, container_name)) }
it { expect(result.scheme).to eq('wss') }
it { expect(result.host).to eq('example.com') }
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index b9d12c3c24c..9dd997aa7dc 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -14,7 +14,7 @@ describe Gitlab::LDAP::Access, lib: true do
it { is_expected.to be_falsey }
- it 'should block user in GitLab' do
+ it 'blocks user in GitLab' do
expect(access).to receive(:block_user).with(user, 'does not exist anymore')
access.allowed?
diff --git a/spec/lib/gitlab/ldap/auth_hash_spec.rb b/spec/lib/gitlab/ldap/auth_hash_spec.rb
index 69c49051156..7a2f774b948 100644
--- a/spec/lib/gitlab/ldap/auth_hash_spec.rb
+++ b/spec/lib/gitlab/ldap/auth_hash_spec.rb
@@ -44,7 +44,7 @@ describe Gitlab::LDAP::AuthHash, lib: true do
context "with overridden attributes" do
let(:attributes) do
{
- 'username' => ['mail', 'email'],
+ 'username' => %w(mail email),
'name' => 'fullName'
}
end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 89790c9e1af..346cf0d117c 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -57,7 +57,7 @@ describe Gitlab::LDAP::User, lib: true do
end
end
- describe :find_or_create do
+ describe 'find or create' do
it "finds the user if already existing" do
create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain')
@@ -95,10 +95,10 @@ describe Gitlab::LDAP::User, lib: true do
it 'maintains an identity per provider' do
existing_user = create(:omniauth_user, email: 'john@example.com', provider: 'twitter')
- expect(existing_user.identities.count).to eql(1)
+ expect(existing_user.identities.count).to be(1)
ldap_user.save
- expect(ldap_user.gl_user.identities.count).to eql(2)
+ expect(ldap_user.gl_user.identities.count).to be(2)
# Expect that find_by provider only returns a single instance of an identity and not an Enumerable
expect(ldap_user.gl_user.identities.find_by(provider: 'twitter')).to be_instance_of Identity
diff --git a/spec/lib/gitlab/metrics/instrumentation_spec.rb b/spec/lib/gitlab/metrics/instrumentation_spec.rb
index d88bcae41fb..a986cb520fb 100644
--- a/spec/lib/gitlab/metrics/instrumentation_spec.rb
+++ b/spec/lib/gitlab/metrics/instrumentation_spec.rb
@@ -197,11 +197,13 @@ describe Gitlab::Metrics::Instrumentation do
@child1 = Class.new(@dummy) do
def self.child1_foo; end
+
def child1_bar; end
end
@child2 = Class.new(@child1) do
def self.child2_foo; end
+
def child2_bar; end
end
end
diff --git a/spec/lib/gitlab/metrics/method_call_spec.rb b/spec/lib/gitlab/metrics/method_call_spec.rb
index 8d05081eecb..a247f03b2da 100644
--- a/spec/lib/gitlab/metrics/method_call_spec.rb
+++ b/spec/lib/gitlab/metrics/method_call_spec.rb
@@ -23,7 +23,7 @@ describe Gitlab::Metrics::MethodCall do
expect(metric.values[:duration]).to be_a_kind_of(Numeric)
expect(metric.values[:cpu_duration]).to be_a_kind_of(Numeric)
- expect(metric.values[:call_count]).to an_instance_of(Fixnum)
+ expect(metric.values[:call_count]).to be_an(Integer)
expect(metric.tags).to eq({ method: 'Foo#bar' })
end
diff --git a/spec/lib/gitlab/metrics/metric_spec.rb b/spec/lib/gitlab/metrics/metric_spec.rb
index f26fca52c50..d240b8a01fd 100644
--- a/spec/lib/gitlab/metrics/metric_spec.rb
+++ b/spec/lib/gitlab/metrics/metric_spec.rb
@@ -62,7 +62,7 @@ describe Gitlab::Metrics::Metric do
end
it 'includes the timestamp' do
- expect(hash[:timestamp]).to be_an_instance_of(Fixnum)
+ expect(hash[:timestamp]).to be_an(Integer)
end
end
end
diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb
index 9e2ea89a712..4d94d8705fb 100644
--- a/spec/lib/gitlab/metrics/system_spec.rb
+++ b/spec/lib/gitlab/metrics/system_spec.rb
@@ -29,19 +29,19 @@ describe Gitlab::Metrics::System do
describe '.cpu_time' do
it 'returns a Fixnum' do
- expect(described_class.cpu_time).to be_an_instance_of(Fixnum)
+ expect(described_class.cpu_time).to be_an(Integer)
end
end
describe '.real_time' do
it 'returns a Fixnum' do
- expect(described_class.real_time).to be_an_instance_of(Fixnum)
+ expect(described_class.real_time).to be_an(Integer)
end
end
describe '.monotonic_time' do
it 'returns a Fixnum' do
- expect(described_class.monotonic_time).to be_an_instance_of(Fixnum)
+ expect(described_class.monotonic_time).to be_an(Integer)
end
end
end
diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb
index 3887c04c832..0c5a6246d85 100644
--- a/spec/lib/gitlab/metrics/transaction_spec.rb
+++ b/spec/lib/gitlab/metrics/transaction_spec.rb
@@ -134,7 +134,7 @@ describe Gitlab::Metrics::Transaction do
series: 'rails_transactions',
tags: { action: 'Foo#bar' },
values: { duration: 0.0, allocated_memory: a_kind_of(Numeric) },
- timestamp: an_instance_of(Fixnum)
+ timestamp: a_kind_of(Integer)
}
expect(Gitlab::Metrics).to receive(:submit_metrics).
@@ -151,7 +151,7 @@ describe Gitlab::Metrics::Transaction do
series: 'events',
tags: { event: :meow },
values: { count: 1 },
- timestamp: an_instance_of(Fixnum)
+ timestamp: a_kind_of(Integer)
}
expect(Gitlab::Metrics).to receive(:submit_metrics).
diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb
index fd3769d75b5..c2ab015d5cb 100644
--- a/spec/lib/gitlab/middleware/go_spec.rb
+++ b/spec/lib/gitlab/middleware/go_spec.rb
@@ -15,16 +15,93 @@ describe Gitlab::Middleware::Go, lib: true do
end
describe 'when go-get=1' do
- it 'returns a document' do
- env = { 'rack.input' => '',
- 'QUERY_STRING' => 'go-get=1',
- 'PATH_INFO' => '/group/project/path' }
- resp = middleware.call(env)
- expect(resp[0]).to eq(200)
- expect(resp[1]['Content-Type']).to eq('text/html')
- expected_body = "<!DOCTYPE html><html><head><meta content='#{Gitlab.config.gitlab.host}/group/project git http://#{Gitlab.config.gitlab.host}/group/project.git' name='go-import'></head></html>\n"
- expect(resp[2].body).to eq([expected_body])
+ let(:current_user) { nil }
+
+ context 'with simple 2-segment project path' do
+ let!(:project) { create(:project, :private) }
+
+ context 'with subpackages' do
+ let(:path) { "#{project.full_path}/subpackage" }
+
+ it 'returns the full project path' do
+ expect_response_with_path(go, project.full_path)
+ end
+ end
+
+ context 'without subpackages' do
+ let(:path) { project.full_path }
+
+ it 'returns the full project path' do
+ expect_response_with_path(go, project.full_path)
+ end
+ end
+ end
+
+ context 'with a nested project path' do
+ let(:group) { create(:group, :nested) }
+ let!(:project) { create(:project, :public, namespace: group) }
+
+ shared_examples 'a nested project' do
+ context 'when the project is public' do
+ it 'returns the full project path' do
+ expect_response_with_path(go, project.full_path)
+ end
+ end
+
+ context 'when the project is private' do
+ before do
+ project.update_attribute(:visibility_level, Project::PRIVATE)
+ end
+
+ context 'with access to the project' do
+ let(:current_user) { project.creator }
+
+ before do
+ project.team.add_master(current_user)
+ end
+
+ it 'returns the full project path' do
+ expect_response_with_path(go, project.full_path)
+ end
+ end
+
+ context 'without access to the project' do
+ it 'returns the 2-segment group path' do
+ expect_response_with_path(go, group.full_path)
+ end
+ end
+ end
+ end
+
+ context 'with subpackages' do
+ let(:path) { "#{project.full_path}/subpackage" }
+
+ it_behaves_like 'a nested project'
+ end
+
+ context 'without subpackages' do
+ let(:path) { project.full_path }
+
+ it_behaves_like 'a nested project'
+ end
end
end
+
+ def go
+ env = {
+ 'rack.input' => '',
+ 'QUERY_STRING' => 'go-get=1',
+ 'PATH_INFO' => "/#{path}",
+ 'warden' => double(authenticate: current_user)
+ }
+ middleware.call(env)
+ end
+
+ def expect_response_with_path(response, path)
+ expect(response[0]).to eq(200)
+ expect(response[1]['Content-Type']).to eq('text/html')
+ expected_body = "<!DOCTYPE html><html><head><meta content='#{Gitlab.config.gitlab.host}/#{path} git http://#{Gitlab.config.gitlab.host}/#{path}.git' name='go-import'></head></html>\n"
+ expect(response[2].body).to eq([expected_body])
+ end
end
end
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index fc9e1cb430a..6c84a4c8b73 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -148,12 +148,14 @@ describe Gitlab::OAuth::User, lib: true do
expect(gl_user).to be_valid
expect(gl_user.username).to eql uid
expect(gl_user.email).to eql 'johndoe@example.com'
- expect(gl_user.identities.length).to eql 2
+ expect(gl_user.identities.length).to be 2
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
expect(identities_as_hash).to match_array(
- [ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ [
+ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
{ provider: 'twitter', extern_uid: uid }
- ])
+ ]
+ )
end
end
@@ -167,12 +169,14 @@ describe Gitlab::OAuth::User, lib: true do
expect(gl_user).to be_valid
expect(gl_user.username).to eql 'john'
expect(gl_user.email).to eql 'john@example.com'
- expect(gl_user.identities.length).to eql 2
+ expect(gl_user.identities.length).to be 2
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
expect(identities_as_hash).to match_array(
- [ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ [
+ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
{ provider: 'twitter', extern_uid: uid }
- ])
+ ]
+ )
end
end
diff --git a/spec/lib/gitlab/optimistic_locking_spec.rb b/spec/lib/gitlab/optimistic_locking_spec.rb
index 498dc514c8c..acce2be93f2 100644
--- a/spec/lib/gitlab/optimistic_locking_spec.rb
+++ b/spec/lib/gitlab/optimistic_locking_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
describe Gitlab::OptimisticLocking, lib: true do
- describe '#retry_lock' do
- let!(:pipeline) { create(:ci_pipeline) }
- let!(:pipeline2) { Ci::Pipeline.find(pipeline.id) }
+ let!(:pipeline) { create(:ci_pipeline) }
+ let!(:pipeline2) { Ci::Pipeline.find(pipeline.id) }
+ describe '#retry_lock' do
it 'does not reload object if state changes' do
expect(pipeline).not_to receive(:reload)
expect(pipeline).to receive(:succeed).and_call_original
@@ -36,4 +36,17 @@ describe Gitlab::OptimisticLocking, lib: true do
end.to raise_error(ActiveRecord::StaleObjectError)
end
end
+
+ describe '#retry_optimistic_lock' do
+ context 'when locking module is mixed in' do
+ let(:unlockable) do
+ Class.new.include(described_class).new
+ end
+
+ it 'is an alias for retry_lock' do
+ expect(unlockable.method(:retry_optimistic_lock))
+ .to eq unlockable.method(:retry_lock)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/other_markup.rb b/spec/lib/gitlab/other_markup.rb
new file mode 100644
index 00000000000..8f5a353b381
--- /dev/null
+++ b/spec/lib/gitlab/other_markup.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe Gitlab::OtherMarkup, lib: true do
+ context "XSS Checks" do
+ links = {
+ 'links' => {
+ file: 'file.rdoc',
+ input: 'XSS[JaVaScriPt:alert(1)]',
+ output: '<p><a>XSS</a></p>'
+ }
+ }
+ links.each do |name, data|
+ it "does not convert dangerous #{name} into HTML" do
+ expect(render(data[:file], data[:input], context)).to eql data[:output]
+ end
+ end
+ end
+
+ def render(*args)
+ described_class.render(*args)
+ end
+end
diff --git a/spec/lib/gitlab/polling_interval_spec.rb b/spec/lib/gitlab/polling_interval_spec.rb
new file mode 100644
index 00000000000..56c2847e26a
--- /dev/null
+++ b/spec/lib/gitlab/polling_interval_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Gitlab::PollingInterval, lib: true do
+ let(:polling_interval) { described_class }
+
+ describe '.set_header' do
+ let(:headers) { {} }
+ let(:response) { double(headers: headers) }
+
+ context 'when polling is disabled' do
+ before do
+ stub_application_setting(polling_interval_multiplier: 0)
+ end
+
+ it 'sets value to -1' do
+ polling_interval.set_header(response, interval: 10_000)
+
+ expect(headers['Poll-Interval']).to eq(-1)
+ end
+ end
+
+ context 'when polling is enabled' do
+ before do
+ stub_application_setting(polling_interval_multiplier: 0.33333)
+ end
+
+ it 'applies modifier to base interval' do
+ polling_interval.set_header(response, interval: 10_000)
+
+ expect(headers['Poll-Interval']).to eq(3333)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 14ee386dba6..9a8096208db 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::ProjectSearchResults, lib: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:query) { 'hello world' }
describe 'initialize with empty ref' do
@@ -22,6 +22,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
describe 'blob search' do
+ let(:project) { create(:project, :repository) }
let(:results) { described_class.new(user, project, 'files').objects('blobs') }
it 'finds by name' do
@@ -74,6 +75,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
describe 'confidential issues' do
+ let(:project) { create(:empty_project) }
let(:query) { 'issue' }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
@@ -161,7 +163,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
it "doesn't list issue notes when access is restricted" do
- project = create(:empty_project, :public, issues_access_level: ProjectFeature::PRIVATE)
+ project = create(:empty_project, :public, :issues_private)
note = create(:note_on_issue, project: project)
results = described_class.new(user, project, note.note)
@@ -170,7 +172,7 @@ describe Gitlab::ProjectSearchResults, lib: true do
end
it "doesn't list merge_request notes when access is restricted" do
- project = create(:empty_project, :public, merge_requests_access_level: ProjectFeature::PRIVATE)
+ project = create(:empty_project, :public, :merge_requests_private)
note = create(:note_on_merge_request, project: project)
results = described_class.new(user, project, note.note)
@@ -178,4 +180,119 @@ describe Gitlab::ProjectSearchResults, lib: true do
expect(results.objects('notes')).not_to include note
end
end
+
+ # Examples for commit access level test
+ #
+ # params:
+ # * search_phrase
+ # * commit
+ #
+ shared_examples 'access restricted commits' do
+ context 'when project is internal' do
+ let(:project) { create(:project, :internal, :repository) }
+
+ it 'does not search if user is not authenticated' do
+ commits = described_class.new(nil, project, search_phrase).objects('commits')
+
+ expect(commits).to be_empty
+ end
+
+ it 'searches if user is authenticated' do
+ commits = described_class.new(user, project, search_phrase).objects('commits')
+
+ expect(commits).to contain_exactly commit
+ end
+ end
+
+ context 'when project is private' do
+ let!(:creator) { create(:user, username: 'private-project-author') }
+ let!(:private_project) { create(:project, :private, :repository, creator: creator, namespace: creator.namespace) }
+ let(:team_master) do
+ user = create(:user, username: 'private-project-master')
+ private_project.team << [user, :master]
+ user
+ end
+ let(:team_reporter) do
+ user = create(:user, username: 'private-project-reporter')
+ private_project.team << [user, :reporter]
+ user
+ end
+
+ it 'does not show commit to stranger' do
+ commits = described_class.new(nil, private_project, search_phrase).objects('commits')
+
+ expect(commits).to be_empty
+ end
+
+ context 'team access' do
+ it 'shows commit to creator' do
+ commits = described_class.new(creator, private_project, search_phrase).objects('commits')
+
+ expect(commits).to contain_exactly commit
+ end
+
+ it 'shows commit to master' do
+ commits = described_class.new(team_master, private_project, search_phrase).objects('commits')
+
+ expect(commits).to contain_exactly commit
+ end
+
+ it 'shows commit to reporter' do
+ commits = described_class.new(team_reporter, private_project, search_phrase).objects('commits')
+
+ expect(commits).to contain_exactly commit
+ end
+ end
+ end
+ end
+
+ describe 'commit search' do
+ context 'by commit message' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:commit) { project.repository.commit('59e29889be61e6e0e5e223bfa9ac2721d31605b8') }
+ let(:message) { 'Sorry, I did a mistake' }
+
+ it 'finds commit by message' do
+ commits = described_class.new(user, project, message).objects('commits')
+
+ expect(commits).to contain_exactly commit
+ end
+
+ it 'handles when no commit match' do
+ commits = described_class.new(user, project, 'not really an existing description').objects('commits')
+
+ expect(commits).to be_empty
+ end
+
+ it_behaves_like 'access restricted commits' do
+ let(:search_phrase) { message }
+ let(:commit) { project.repository.commit('59e29889be61e6e0e5e223bfa9ac2721d31605b8') }
+ end
+ end
+
+ context 'by commit hash' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:commit) { project.repository.commit('0b4bc9a') }
+ commit_hashes = { short: '0b4bc9a', full: '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
+
+ commit_hashes.each do |type, commit_hash|
+ it "shows commit by #{type} hash id" do
+ commits = described_class.new(user, project, commit_hash).objects('commits')
+
+ expect(commits).to contain_exactly commit
+ end
+ end
+
+ it 'handles not existing commit hash correctly' do
+ commits = described_class.new(user, project, 'deadbeef').objects('commits')
+
+ expect(commits).to be_empty
+ end
+
+ it_behaves_like 'access restricted commits' do
+ let(:search_phrase) { '0b4bc9a49' }
+ let(:commit) { project.repository.commit('0b4bc9a') }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/project_transfer_spec.rb
index 4092f7fb638..e2d6b1b9ab7 100644
--- a/spec/lib/gitlab/uploads_transfer_spec.rb
+++ b/spec/lib/gitlab/project_transfer_spec.rb
@@ -1,9 +1,10 @@
require 'spec_helper'
-describe Gitlab::UploadsTransfer, lib: true do
+describe Gitlab::ProjectTransfer, lib: true do
before do
@root_dir = File.join(Rails.root, "public", "uploads")
- @upload_transfer = Gitlab::UploadsTransfer.new
+ @project_transfer = Gitlab::ProjectTransfer.new
+ allow(@project_transfer).to receive(:root_dir).and_return(@root_dir)
@project_path_was = "test_project_was"
@project_path = "test_project"
@@ -21,7 +22,7 @@ describe Gitlab::UploadsTransfer, lib: true do
describe '#move_project' do
it "moves project upload to another namespace" do
FileUtils.mkdir_p(File.join(@root_dir, @namespace_path_was, @project_path))
- @upload_transfer.move_project(@project_path, @namespace_path_was, @namespace_path)
+ @project_transfer.move_project(@project_path, @namespace_path_was, @namespace_path)
expected_path = File.join(@root_dir, @namespace_path, @project_path)
expect(Dir.exist?(expected_path)).to be_truthy
@@ -31,7 +32,7 @@ describe Gitlab::UploadsTransfer, lib: true do
describe '#rename_project' do
it "renames project" do
FileUtils.mkdir_p(File.join(@root_dir, @namespace_path, @project_path_was))
- @upload_transfer.rename_project(@project_path_was, @project_path, @namespace_path)
+ @project_transfer.rename_project(@project_path_was, @project_path, @namespace_path)
expected_path = File.join(@root_dir, @namespace_path, @project_path)
expect(Dir.exist?(expected_path)).to be_truthy
@@ -41,7 +42,7 @@ describe Gitlab::UploadsTransfer, lib: true do
describe '#rename_namespace' do
it "renames namespace" do
FileUtils.mkdir_p(File.join(@root_dir, @namespace_path_was, @project_path))
- @upload_transfer.rename_namespace(@namespace_path_was, @namespace_path)
+ @project_transfer.rename_namespace(@namespace_path_was, @namespace_path)
expected_path = File.join(@root_dir, @namespace_path, @project_path)
expect(Dir.exist?(expected_path)).to be_truthy
diff --git a/spec/lib/gitlab/prometheus_spec.rb b/spec/lib/gitlab/prometheus_spec.rb
new file mode 100644
index 00000000000..280264188e2
--- /dev/null
+++ b/spec/lib/gitlab/prometheus_spec.rb
@@ -0,0 +1,143 @@
+require 'spec_helper'
+
+describe Gitlab::Prometheus, lib: true do
+ include PrometheusHelpers
+
+ subject { described_class.new(api_url: 'https://prometheus.example.com') }
+
+ describe '#ping' do
+ it 'issues a "query" request to the API endpoint' do
+ req_stub = stub_prometheus_request(prometheus_query_url('1'), body: prometheus_value_body('vector'))
+
+ expect(subject.ping).to eq({ "resultType" => "vector", "result" => [{ "metric" => {}, "value" => [1488772511.004, "0.000041021495238095323"] }] })
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ # This shared examples expect:
+ # - query_url: A query URL
+ # - execute_query: A query call
+ shared_examples 'failure response' do
+ context 'when request returns 400 with an error message' do
+ it 'raises a Gitlab::PrometheusError error' do
+ req_stub = stub_prometheus_request(query_url, status: 400, body: { error: 'bar!' })
+
+ expect { execute_query }
+ .to raise_error(Gitlab::PrometheusError, 'bar!')
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns 400 without an error message' do
+ it 'raises a Gitlab::PrometheusError error' do
+ req_stub = stub_prometheus_request(query_url, status: 400)
+
+ expect { execute_query }
+ .to raise_error(Gitlab::PrometheusError, 'Bad data received')
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns 500' do
+ it 'raises a Gitlab::PrometheusError error' do
+ req_stub = stub_prometheus_request(query_url, status: 500, body: { message: 'FAIL!' })
+
+ expect { execute_query }
+ .to raise_error(Gitlab::PrometheusError, '500 - {"message":"FAIL!"}')
+ expect(req_stub).to have_been_requested
+ end
+ end
+ end
+
+ describe '#query' do
+ let(:prometheus_query) { prometheus_cpu_query('env-slug') }
+ let(:query_url) { prometheus_query_url(prometheus_query) }
+
+ context 'when request returns vector results' do
+ it 'returns data from the API call' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_value_body('vector'))
+
+ expect(subject.query(prometheus_query)).to eq [{ "metric" => {}, "value" => [1488772511.004, "0.000041021495238095323"] }]
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns matrix results' do
+ it 'returns nil' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_value_body('matrix'))
+
+ expect(subject.query(prometheus_query)).to be_nil
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns no data' do
+ it 'returns []' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_empty_body('vector'))
+
+ expect(subject.query(prometheus_query)).to be_empty
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ it_behaves_like 'failure response' do
+ let(:execute_query) { subject.query(prometheus_query) }
+ end
+ end
+
+ describe '#query_range' do
+ let(:prometheus_query) { prometheus_memory_query('env-slug') }
+ let(:query_url) { prometheus_query_range_url(prometheus_query) }
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ context 'when a start time is passed' do
+ let(:query_url) { prometheus_query_range_url(prometheus_query, start: 2.hours.ago) }
+
+ it 'passed it in the requested URL' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_values_body('vector'))
+
+ subject.query_range(prometheus_query, start: 2.hours.ago)
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns vector results' do
+ it 'returns nil' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_values_body('vector'))
+
+ expect(subject.query_range(prometheus_query)).to be_nil
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns matrix results' do
+ it 'returns data from the API call' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_values_body('matrix'))
+
+ expect(subject.query_range(prometheus_query)).to eq([
+ {
+ "metric" => {},
+ "values" => [[1488758662.506, "0.00002996364761904785"], [1488758722.506, "0.00003090239047619091"]]
+ }
+ ])
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ context 'when request returns no data' do
+ it 'returns []' do
+ req_stub = stub_prometheus_request(query_url, body: prometheus_empty_body('matrix'))
+
+ expect(subject.query_range(prometheus_query)).to be_empty
+ expect(req_stub).to have_been_requested
+ end
+ end
+
+ it_behaves_like 'failure response' do
+ let(:execute_query) { subject.query_range(prometheus_query) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/redis_spec.rb b/spec/lib/gitlab/redis_spec.rb
index 917c5c46db1..8b77c925705 100644
--- a/spec/lib/gitlab/redis_spec.rb
+++ b/spec/lib/gitlab/redis_spec.rb
@@ -3,8 +3,16 @@ require 'spec_helper'
describe Gitlab::Redis do
include StubENV
- before(:each) { clear_raw_config }
- after(:each) { clear_raw_config }
+ let(:config) { 'config/resque.yml' }
+
+ before(:each) do
+ stub_env('GITLAB_REDIS_CONFIG_FILE', Rails.root.join(config).to_s)
+ clear_raw_config
+ end
+
+ after(:each) do
+ clear_raw_config
+ end
describe '.params' do
subject { described_class.params }
@@ -18,22 +26,22 @@ describe Gitlab::Redis do
end
context 'when url contains unix socket reference' do
- let(:config_old) { Rails.root.join('spec/fixtures/config/redis_old_format_socket.yml').to_s }
- let(:config_new) { Rails.root.join('spec/fixtures/config/redis_new_format_socket.yml').to_s }
+ let(:config_old) { 'spec/fixtures/config/redis_old_format_socket.yml' }
+ let(:config_new) { 'spec/fixtures/config/redis_new_format_socket.yml' }
context 'with old format' do
- it 'returns path key instead' do
- stub_const("#{described_class}::CONFIG_FILE", config_old)
+ let(:config) { config_old }
+ it 'returns path key instead' do
is_expected.to include(path: '/path/to/old/redis.sock')
is_expected.not_to have_key(:url)
end
end
context 'with new format' do
- it 'returns path key instead' do
- stub_const("#{described_class}::CONFIG_FILE", config_new)
+ let(:config) { config_new }
+ it 'returns path key instead' do
is_expected.to include(path: '/path/to/redis.sock')
is_expected.not_to have_key(:url)
end
@@ -41,22 +49,22 @@ describe Gitlab::Redis do
end
context 'when url is host based' do
- let(:config_old) { Rails.root.join('spec/fixtures/config/redis_old_format_host.yml') }
- let(:config_new) { Rails.root.join('spec/fixtures/config/redis_new_format_host.yml') }
+ let(:config_old) { 'spec/fixtures/config/redis_old_format_host.yml' }
+ let(:config_new) { 'spec/fixtures/config/redis_new_format_host.yml' }
context 'with old format' do
- it 'returns hash with host, port, db, and password' do
- stub_const("#{described_class}::CONFIG_FILE", config_old)
+ let(:config) { config_old }
+ it 'returns hash with host, port, db, and password' do
is_expected.to include(host: 'localhost', password: 'mypassword', port: 6379, db: 99)
is_expected.not_to have_key(:url)
end
end
context 'with new format' do
- it 'returns hash with host, port, db, and password' do
- stub_const("#{described_class}::CONFIG_FILE", config_new)
+ let(:config) { config_new }
+ it 'returns hash with host, port, db, and password' do
is_expected.to include(host: 'localhost', password: 'mynewpassword', port: 6379, db: 99)
is_expected.not_to have_key(:url)
end
@@ -74,15 +82,13 @@ describe Gitlab::Redis do
end
context 'when yml file with env variable' do
- let(:redis_config) { Rails.root.join('spec/fixtures/config/redis_config_with_env.yml') }
+ let(:config) { 'spec/fixtures/config/redis_config_with_env.yml' }
before do
stub_env('TEST_GITLAB_REDIS_URL', 'redis://redishost:6379')
end
it 'reads redis url from env variable' do
- stub_const("#{described_class}::CONFIG_FILE", redis_config)
-
expect(described_class.url).to eq 'redis://redishost:6379'
end
end
@@ -90,14 +96,13 @@ describe Gitlab::Redis do
describe '._raw_config' do
subject { described_class._raw_config }
+ let(:config) { '/var/empty/doesnotexist' }
it 'should be frozen' do
expect(subject).to be_frozen
end
it 'returns false when the file does not exist' do
- stub_const("#{described_class}::CONFIG_FILE", '/var/empty/doesnotexist')
-
expect(subject).to eq(false)
end
end
@@ -134,22 +139,18 @@ describe Gitlab::Redis do
subject { described_class.new(Rails.env).sentinels }
context 'when sentinels are defined' do
- let(:config) { Rails.root.join('spec/fixtures/config/redis_new_format_host.yml') }
+ let(:config) { 'spec/fixtures/config/redis_new_format_host.yml' }
it 'returns an array of hashes with host and port keys' do
- stub_const("#{described_class}::CONFIG_FILE", config)
-
is_expected.to include(host: 'localhost', port: 26380)
is_expected.to include(host: 'slave2', port: 26381)
end
end
context 'when sentinels are not defined' do
- let(:config) { Rails.root.join('spec/fixtures/config/redis_old_format_host.yml') }
+ let(:config) { 'spec/fixtures/config/redis_old_format_host.yml' }
it 'returns nil' do
- stub_const("#{described_class}::CONFIG_FILE", config)
-
is_expected.to be_nil
end
end
@@ -159,21 +160,17 @@ describe Gitlab::Redis do
subject { described_class.new(Rails.env).sentinels? }
context 'when sentinels are defined' do
- let(:config) { Rails.root.join('spec/fixtures/config/redis_new_format_host.yml') }
+ let(:config) { 'spec/fixtures/config/redis_new_format_host.yml' }
it 'returns true' do
- stub_const("#{described_class}::CONFIG_FILE", config)
-
is_expected.to be_truthy
end
end
context 'when sentinels are not defined' do
- let(:config) { Rails.root.join('spec/fixtures/config/redis_old_format_host.yml') }
+ let(:config) { 'spec/fixtures/config/redis_old_format_host.yml' }
it 'returns false' do
- stub_const("#{described_class}::CONFIG_FILE", config)
-
is_expected.to be_falsey
end
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index bf0ab9635fd..84cfd934fa0 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -1,9 +1,11 @@
require 'spec_helper'
describe Gitlab::ReferenceExtractor, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
- before { project.team << [project.creator, :developer] }
+ before do
+ project.team << [project.creator, :developer]
+ end
subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
@@ -40,14 +42,85 @@ describe Gitlab::ReferenceExtractor, lib: true do
> @offteam
})
+
expect(subject.users).to match_array([])
end
+ describe 'directly addressed users' do
+ before do
+ @u_foo = create(:user, username: 'foo')
+ @u_foo2 = create(:user, username: 'foo2')
+ @u_foo3 = create(:user, username: 'foo3')
+ @u_foo4 = create(:user, username: 'foo4')
+ @u_foo5 = create(:user, username: 'foo5')
+
+ @u_bar = create(:user, username: 'bar')
+ @u_bar2 = create(:user, username: 'bar2')
+ @u_bar3 = create(:user, username: 'bar3')
+ @u_bar4 = create(:user, username: 'bar4')
+
+ @u_tom = create(:user, username: 'tom')
+ @u_tom2 = create(:user, username: 'tom2')
+ end
+
+ context 'when a user is directly addressed' do
+ it 'accesses the user object which is mentioned in the beginning of the line' do
+ subject.analyze('@foo What do you think? cc: @bar, @tom')
+
+ expect(subject.directly_addressed_users).to match_array([@u_foo])
+ end
+
+ it "doesn't access the user object if it's not mentioned in the beginning of the line" do
+ subject.analyze('What do you think? cc: @bar')
+
+ expect(subject.directly_addressed_users).to be_empty
+ end
+ end
+
+ context 'when multiple users are addressed' do
+ it 'accesses the user objects which are mentioned in the beginning of the line' do
+ subject.analyze('@foo @bar What do you think? cc: @tom')
+
+ expect(subject.directly_addressed_users).to match_array([@u_foo, @u_bar])
+ end
+
+ it "doesn't access the user objects if they are not mentioned in the beginning of the line" do
+ subject.analyze('What do you think? cc: @foo @bar @tom')
+
+ expect(subject.directly_addressed_users).to be_empty
+ end
+ end
+
+ context 'when multiple users are addressed in different paragraphs' do
+ it 'accesses user objects which are mentioned in the beginning of each paragraph' do
+ subject.analyze <<-NOTE.strip_heredoc
+ @foo What do you think? cc: @tom
+
+ - @bar can you please have a look?
+
+ >>>
+ @foo2 what do you think? cc: @bar2
+ >>>
+
+ @foo3 @foo4 thank you!
+
+ > @foo5 well done!
+
+ 1. @bar3 Can you please check? cc: @tom2
+ 2. @bar4 What do you this of this MR?
+ NOTE
+
+ expect(subject.directly_addressed_users).to match_array([@u_foo, @u_foo3, @u_foo4])
+ end
+ end
+ end
+
it 'accesses valid issue objects' do
@i0 = create(:issue, project: project)
@i1 = create(:issue, project: project)
subject.analyze("#{@i0.to_reference}, #{@i1.to_reference}, and #{Issue.reference_prefix}999.")
+
expect(subject.issues).to match_array([@i0, @i1])
end
@@ -56,6 +129,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
@m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'feature_conflict')
subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.")
+
expect(subject.merge_requests).to match_array([@m1, @m0])
end
@@ -65,6 +139,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
@l2 = create(:label)
subject.analyze("~#{@l0.id}, ~999, ~#{@l2.id}, ~#{@l1.id}")
+
expect(subject.labels).to match_array([@l0, @l1])
end
@@ -74,26 +149,32 @@ describe Gitlab::ReferenceExtractor, lib: true do
@s2 = create(:project_snippet)
subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}")
+
expect(subject.snippets).to match_array([@s0, @s1])
end
it 'accesses valid commits' do
+ project = create(:project, :repository) { |p| p.add_developer(p.creator) }
commit = project.commit('master')
- subject.analyze("this references commits #{commit.sha[0..6]} and 012345")
- extracted = subject.commits
+ extractor = described_class.new(project, project.creator)
+ extractor.analyze("this references commits #{commit.sha[0..6]} and 012345")
+ extracted = extractor.commits
+
expect(extracted.size).to eq(1)
expect(extracted[0].sha).to eq(commit.sha)
expect(extracted[0].message).to eq(commit.message)
end
it 'accesses valid commit ranges' do
+ project = create(:project, :repository) { |p| p.add_developer(p.creator) }
commit = project.commit('master')
earlier_commit = project.commit('master~2')
- subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}")
+ extractor = described_class.new(project, project.creator)
+ extractor.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}")
+ extracted = extractor.commit_ranges
- extracted = subject.commit_ranges
expect(extracted.size).to eq(1)
expect(extracted.first).to be_kind_of(CommitRange)
expect(extracted.first.commit_from).to eq earlier_commit
@@ -102,7 +183,6 @@ describe Gitlab::ReferenceExtractor, lib: true do
context 'with an external issue tracker' do
let(:project) { create(:jira_project) }
- subject { described_class.new(project, project.creator) }
it 'returns JIRA issues for a JIRA-integrated project' do
subject.analyze('JIRA-123 and FOOBAR-4567')
@@ -112,7 +192,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
end
context 'with a project with an underscore' do
- let(:other_project) { create(:project, path: 'test_project') }
+ let(:other_project) { create(:empty_project, path: 'test_project') }
let(:issue) { create(:issue, project: other_project) }
before do
@@ -121,6 +201,7 @@ describe Gitlab::ReferenceExtractor, lib: true do
it 'handles project issue references' do
subject.analyze("this refers issue #{issue.to_reference(project)}")
+
extracted = subject.issues
expect(extracted.size).to eq(1)
expect(extracted).to match_array([issue])
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index c78cd30157e..ba45e2d758c 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -2,47 +2,64 @@
require 'spec_helper'
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) }
- it { expect('_underscore.js').to match(Gitlab::Regex.project_path_regex) }
- it { expect('100px.com').to match(Gitlab::Regex.project_path_regex) }
- it { expect('?gitlab').not_to match(Gitlab::Regex.project_path_regex) }
- it { expect('git lab').not_to match(Gitlab::Regex.project_path_regex) }
- it { expect('gitlab.git').not_to match(Gitlab::Regex.project_path_regex) }
+ describe '.project_path_regex' do
+ subject { described_class.project_path_regex }
+
+ it { is_expected.to match('gitlab-ce') }
+ it { is_expected.to match('gitlab_git') }
+ it { is_expected.to match('_underscore.js') }
+ it { is_expected.to match('100px.com') }
+ it { is_expected.not_to match('?gitlab') }
+ it { is_expected.not_to match('git lab') }
+ it { is_expected.not_to match('gitlab.git') }
end
- describe 'project name regex' do
- it { expect('gitlab-ce').to match(Gitlab::Regex.project_name_regex) }
- it { expect('GitLab CE').to match(Gitlab::Regex.project_name_regex) }
- it { expect('100 lines').to match(Gitlab::Regex.project_name_regex) }
- it { expect('gitlab.git').to match(Gitlab::Regex.project_name_regex) }
- it { expect('Český název').to match(Gitlab::Regex.project_name_regex) }
- it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) }
- it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) }
+ describe '.project_name_regex' do
+ subject { described_class.project_name_regex }
+
+ it { is_expected.to match('gitlab-ce') }
+ it { is_expected.to match('GitLab CE') }
+ it { is_expected.to match('100 lines') }
+ it { is_expected.to match('gitlab.git') }
+ it { is_expected.to match('Český název') }
+ it { is_expected.to match('Dash – is this') }
+ it { is_expected.not_to match('?gitlab') }
end
- describe 'file name regex' do
- it { expect('foo@bar').to match(Gitlab::Regex.file_name_regex) }
+ describe '.file_name_regex' do
+ subject { described_class.file_name_regex }
+
+ it { is_expected.to match('foo@bar') }
end
- describe 'file path regex' do
- it { expect('foo@/bar').to match(Gitlab::Regex.file_path_regex) }
+ describe '.file_path_regex' do
+ subject { described_class.file_path_regex }
+
+ it { is_expected.to match('foo@/bar') }
end
- describe 'environment slug regex' do
- def be_matched
- match(Gitlab::Regex.environment_slug_regex)
- end
+ describe '.environment_slug_regex' do
+ subject { described_class.environment_slug_regex }
+
+ it { is_expected.to match('foo') }
+ it { is_expected.to match('foo-1') }
+ it { is_expected.not_to match('FOO') }
+ it { is_expected.not_to match('foo/1') }
+ it { is_expected.not_to match('foo.1') }
+ it { is_expected.not_to match('foo*1') }
+ it { is_expected.not_to match('9foo') }
+ it { is_expected.not_to match('foo-') }
+ end
- it { expect('foo').to be_matched }
- it { expect('foo-1').to be_matched }
+ describe 'FULL_NAMESPACE_REGEX_STR' do
+ subject { %r{\A#{Gitlab::Regex::FULL_NAMESPACE_REGEX_STR}\z} }
- it { expect('FOO').not_to be_matched }
- it { expect('foo/1').not_to be_matched }
- it { expect('foo.1').not_to be_matched }
- it { expect('foo*1').not_to be_matched }
- it { expect('9foo').not_to be_matched }
- it { expect('foo-').not_to be_matched }
+ it { is_expected.to match('gitlab.org') }
+ it { is_expected.to match('gitlab.org/gitlab-git') }
+ it { is_expected.not_to match('gitlab.org.') }
+ it { is_expected.not_to match('gitlab.org/') }
+ it { is_expected.not_to match('/gitlab.org') }
+ it { is_expected.not_to match('gitlab.git') }
+ it { is_expected.not_to match('gitlab git') }
end
end
diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb
new file mode 100644
index 00000000000..0fb5d7646f2
--- /dev/null
+++ b/spec/lib/gitlab/repo_path_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe ::Gitlab::RepoPath do
+ describe '.strip_storage_path' do
+ before do
+ allow(Gitlab.config.repositories).to receive(:storages).and_return({
+ 'storage1' => { 'path' => '/foo' },
+ 'storage2' => { 'path' => '/bar' },
+ })
+ end
+
+ it 'strips the storage path' do
+ expect(described_class.strip_storage_path('/bar/foo/qux/baz.git')).to eq('foo/qux/baz.git')
+ end
+
+ it 'raises NotFoundError if no storage matches the path' do
+ expect { described_class.strip_storage_path('/doesnotexist/foo.git') }.to raise_error(
+ described_class::NotFoundError
+ )
+ end
+ end
+end
diff --git a/spec/lib/gitlab/request_context_spec.rb b/spec/lib/gitlab/request_context_spec.rb
new file mode 100644
index 00000000000..a91c8655cdd
--- /dev/null
+++ b/spec/lib/gitlab/request_context_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe Gitlab::RequestContext, lib: true do
+ describe '#client_ip' do
+ subject { Gitlab::RequestContext.client_ip }
+ let(:app) { -> (env) {} }
+ let(:env) { Hash.new }
+
+ context 'when RequestStore::Middleware is used' do
+ around(:each) do |example|
+ RequestStore::Middleware.new(-> (env) { example.run }).call({})
+ end
+
+ context 'request' do
+ let(:ip) { '192.168.1.11' }
+
+ before do
+ allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip)
+ Gitlab::RequestContext.new(app).call(env)
+ end
+
+ it { is_expected.to eq(ip) }
+ end
+
+ context 'before RequestContext middleware run' do
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/route_map_spec.rb b/spec/lib/gitlab/route_map_spec.rb
new file mode 100644
index 00000000000..2370f56a613
--- /dev/null
+++ b/spec/lib/gitlab/route_map_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+describe Gitlab::RouteMap, lib: true do
+ describe '#initialize' do
+ context 'when the data is not YAML' do
+ it 'raises an error' do
+ expect { described_class.new('"') }.
+ to raise_error(Gitlab::RouteMap::FormatError, /valid YAML/)
+ end
+ end
+
+ context 'when the data is not a YAML array' do
+ it 'raises an error' do
+ expect { described_class.new(YAML.dump('foo')) }.
+ to raise_error(Gitlab::RouteMap::FormatError, /an array/)
+ end
+ end
+
+ context 'when an entry is not a hash' do
+ it 'raises an error' do
+ expect { described_class.new(YAML.dump(['foo'])) }.
+ to raise_error(Gitlab::RouteMap::FormatError, /a hash/)
+ end
+ end
+
+ context 'when an entry does not have a source key' do
+ it 'raises an error' do
+ expect { described_class.new(YAML.dump([{ 'public' => 'index.html' }])) }.
+ to raise_error(Gitlab::RouteMap::FormatError, /source key/)
+ end
+ end
+
+ context 'when an entry does not have a public key' do
+ it 'raises an error' do
+ expect { described_class.new(YAML.dump([{ 'source' => '/index\.html/' }])) }.
+ to raise_error(Gitlab::RouteMap::FormatError, /public key/)
+ end
+ end
+
+ context 'when an entry source is not a valid regex' do
+ it 'raises an error' do
+ expect { described_class.new(YAML.dump([{ 'source' => '/[/', 'public' => 'index.html' }])) }.
+ to raise_error(Gitlab::RouteMap::FormatError, /regular expression/)
+ end
+ end
+
+ context 'when all is good' do
+ it 'returns a route map' do
+ route_map = described_class.new(YAML.dump([{ 'source' => 'index.haml', 'public' => 'index.html' }, { 'source' => '/(.*)\.md/', 'public' => '\1.html' }]))
+
+ expect(route_map.public_path_for_source_path('index.haml')).to eq('index.html')
+ expect(route_map.public_path_for_source_path('foo.md')).to eq('foo.html')
+ end
+ end
+ end
+
+ describe '#public_path_for_source_path' do
+ subject do
+ described_class.new(<<-'MAP'.strip_heredoc)
+ # Team data
+ - source: 'data/team.yml'
+ public: 'team/'
+
+ # Blogposts
+ - source: /source/posts/([0-9]{4})-([0-9]{2})-([0-9]{2})-(.+?)\..*/ # source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb
+ public: '\1/\2/\3/\4/' # 2017/01/30/around-the-world-in-6-releases/
+
+ # HTML files
+ - source: /source/(.+?\.html).*/ # source/index.html.haml
+ public: '\1' # index.html
+
+ # Other files
+ - source: /source/(.*)/ # source/images/blogimages/around-the-world-in-6-releases-cover.png
+ public: '\1' # images/blogimages/around-the-world-in-6-releases-cover.png
+ MAP
+ end
+
+ it 'returns the public path for a provided source path' do
+ expect(subject.public_path_for_source_path('data/team.yml')).to eq('team/')
+
+ expect(subject.public_path_for_source_path('source/posts/2017-01-30-around-the-world-in-6-releases.html.md.erb')).to eq('2017/01/30/around-the-world-in-6-releases/')
+
+ expect(subject.public_path_for_source_path('source/index.html.haml')).to eq('index.html')
+
+ expect(subject.public_path_for_source_path('source/images/blogimages/around-the-world-in-6-releases-cover.png')).to eq('images/blogimages/around-the-world-in-6-releases-cover.png')
+
+ expect(subject.public_path_for_source_path('.gitlab/route-map.yml')).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb
index 02c139f1a0d..4f6ef3c10fc 100644
--- a/spec/lib/gitlab/saml/user_spec.rb
+++ b/spec/lib/gitlab/saml/user_spec.rb
@@ -155,11 +155,10 @@ describe Gitlab::Saml::User, lib: true do
expect(gl_user).to be_valid
expect(gl_user.username).to eql uid
expect(gl_user.email).to eql 'john@mail.com'
- expect(gl_user.identities.length).to eql 2
+ expect(gl_user.identities.length).to be 2
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array([ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
- { provider: 'saml', extern_uid: uid }
- ])
+ expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'saml', extern_uid: uid }])
end
end
@@ -178,11 +177,10 @@ describe Gitlab::Saml::User, lib: true do
expect(gl_user).to be_valid
expect(gl_user.username).to eql 'john'
expect(gl_user.email).to eql 'john@mail.com'
- expect(gl_user.identities.length).to eql 2
+ expect(gl_user.identities.length).to be 2
identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array([ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
- { provider: 'saml', extern_uid: uid }
- ])
+ expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'saml', extern_uid: uid }])
end
it 'saves successfully on subsequent tries, when both identities are present' do
@@ -204,11 +202,10 @@ describe Gitlab::Saml::User, lib: true do
local_gl_user = local_saml_user.gl_user
expect(local_gl_user).to be_valid
- expect(local_gl_user.identities.length).to eql 2
+ expect(local_gl_user.identities.length).to be 2
identities_as_hash = local_gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
- expect(identities_as_hash).to match_array([ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
- { provider: 'saml', extern_uid: 'uid=user1,ou=People,dc=example' }
- ])
+ expect(identities_as_hash).to match_array([{ provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'saml', extern_uid: 'uid=user1,ou=People,dc=example' }])
end
end
end
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index 9614aad3e73..847fb977400 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::SearchResults do
let(:user) { create(:user) }
- let!(:project) { create(:project, name: 'foo') }
+ let!(:project) { create(:empty_project, name: 'foo') }
let!(:issue) { create(:issue, project: project, title: 'foo') }
let!(:merge_request) do
diff --git a/spec/lib/gitlab/serialize/ci/variables_spec.rb b/spec/lib/gitlab/serializer/ci/variables_spec.rb
index 7ea74da5252..c4b7fda5dbb 100644
--- a/spec/lib/gitlab/serialize/ci/variables_spec.rb
+++ b/spec/lib/gitlab/serializer/ci/variables_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Serialize::Ci::Variables do
+describe Gitlab::Serializer::Ci::Variables do
subject do
described_class.load(described_class.dump(object))
end
@@ -13,6 +13,7 @@ describe Gitlab::Serialize::Ci::Variables do
it 'converts keys into strings' do
is_expected.to eq([
{ key: 'key', value: 'value', public: true },
- { key: 'wee', value: 1, public: false }])
+ { key: 'wee', value: 1, public: false }
+ ])
end
end
diff --git a/spec/lib/gitlab/serializer/pagination_spec.rb b/spec/lib/gitlab/serializer/pagination_spec.rb
new file mode 100644
index 00000000000..519eb1b274f
--- /dev/null
+++ b/spec/lib/gitlab/serializer/pagination_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe Gitlab::Serializer::Pagination do
+ let(:request) { spy('request') }
+ let(:response) { spy('response') }
+ let(:headers) { spy('headers') }
+
+ before do
+ allow(request).to receive(:query_parameters)
+ .and_return(params)
+
+ allow(response).to receive(:headers)
+ .and_return(headers)
+ end
+
+ let(:pagination) { described_class.new(request, response) }
+
+ describe '#paginate' do
+ subject { pagination.paginate(resource) }
+
+ let(:resource) { User.all }
+ let(:params) { { page: 1, per_page: 2 } }
+
+ context 'when a multiple resources are present in relation' do
+ before { create_list(:user, 3) }
+
+ it 'correctly paginates the resource' do
+ expect(subject.count).to be 2
+ end
+
+ it 'appends relevant headers' do
+ expect(headers).to receive(:[]=).with('X-Total', '3')
+ expect(headers).to receive(:[]=).with('X-Total-Pages', '2')
+ expect(headers).to receive(:[]=).with('X-Per-Page', '2')
+
+ subject
+ end
+ end
+
+ context 'when an invalid resource is about to be paginated' do
+ let(:resource) { create(:user) }
+
+ it 'raises error' do
+ expect { subject }.to raise_error(
+ described_class::InvalidResourceError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb b/spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb
new file mode 100644
index 00000000000..287bf62d9bd
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_status/client_middleware_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqStatus::ClientMiddleware do
+ describe '#call' do
+ it 'tracks the job in Redis' do
+ expect(Gitlab::SidekiqStatus).to receive(:set).with('123')
+
+ described_class.new.
+ call('Foo', { 'jid' => '123' }, double(:queue), double(:pool)) { nil }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb b/spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb
new file mode 100644
index 00000000000..80728197b8c
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_status/server_middleware_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqStatus::ServerMiddleware do
+ describe '#call' do
+ it 'stops tracking of a job upon completion' do
+ expect(Gitlab::SidekiqStatus).to receive(:unset).with('123')
+
+ ret = described_class.new.
+ call(double(:worker), { 'jid' => '123' }, double(:queue)) { 10 }
+
+ expect(ret).to eq(10)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_status_spec.rb b/spec/lib/gitlab/sidekiq_status_spec.rb
new file mode 100644
index 00000000000..56f06b61afb
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_status_spec.rb
@@ -0,0 +1,76 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqStatus do
+ describe '.set', :redis do
+ it 'stores the job ID' do
+ described_class.set('123')
+
+ key = described_class.key_for('123')
+
+ Sidekiq.redis do |redis|
+ expect(redis.exists(key)).to eq(true)
+ expect(redis.ttl(key) > 0).to eq(true)
+ end
+ end
+ end
+
+ describe '.unset', :redis do
+ it 'removes the job ID' do
+ described_class.set('123')
+ described_class.unset('123')
+
+ key = described_class.key_for('123')
+
+ Sidekiq.redis do |redis|
+ expect(redis.exists(key)).to eq(false)
+ end
+ end
+ end
+
+ describe '.all_completed?', :redis do
+ it 'returns true if all jobs have been completed' do
+ expect(described_class.all_completed?(%w(123))).to eq(true)
+ end
+
+ it 'returns false if a job has not yet been completed' do
+ described_class.set('123')
+
+ expect(described_class.all_completed?(%w(123 456))).to eq(false)
+ end
+ end
+
+ describe '.num_running', :redis do
+ it 'returns 0 if all jobs have been completed' do
+ expect(described_class.num_running(%w(123))).to eq(0)
+ end
+
+ it 'returns 2 if two jobs are still running' do
+ described_class.set('123')
+ described_class.set('456')
+
+ expect(described_class.num_running(%w(123 456 789))).to eq(2)
+ end
+ end
+
+ describe '.num_completed', :redis do
+ it 'returns 1 if all jobs have been completed' do
+ expect(described_class.num_completed(%w(123))).to eq(1)
+ end
+
+ it 'returns 1 if a job has not yet been completed' do
+ described_class.set('123')
+ described_class.set('456')
+
+ expect(described_class.num_completed(%w(123 456 789))).to eq(1)
+ end
+ end
+
+ describe '.key_for' do
+ it 'returns the key for a job ID' do
+ key = described_class.key_for('123')
+
+ expect(key).to be_an_instance_of(String)
+ expect(key).to include('123')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/extractor_spec.rb b/spec/lib/gitlab/slash_commands/extractor_spec.rb
index 1e4954c4af8..d7f77486b3e 100644
--- a/spec/lib/gitlab/slash_commands/extractor_spec.rb
+++ b/spec/lib/gitlab/slash_commands/extractor_spec.rb
@@ -81,6 +81,14 @@ describe Gitlab::SlashCommands::Extractor do
let(:original_msg) { "/assign @joe\nworld" }
let(:final_msg) { "world" }
end
+
+ it 'allows slash in command arguments' do
+ msg = "/assign @joe / @jane\nworld"
+ msg, commands = extractor.extract_commands(msg)
+
+ expect(commands).to eq [['assign', '@joe / @jane']]
+ expect(msg).to eq 'world'
+ end
end
context 'in the middle of content' do
diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb
index d2d334e6413..9213ced7b19 100644
--- a/spec/lib/gitlab/template/issue_template_spec.rb
+++ b/spec/lib/gitlab/template/issue_template_spec.rb
@@ -4,16 +4,15 @@ describe Gitlab::Template::IssueTemplate do
subject { described_class }
let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:file_path_1) { '.gitlab/issue_templates/bug.md' }
- let(:file_path_2) { '.gitlab/issue_templates/template_test.md' }
- let(:file_path_3) { '.gitlab/issue_templates/feature_proposal.md' }
-
- before do
- project.add_user(user, Gitlab::Access::MASTER)
- project.repository.commit_file(user, file_path_1, "something valid", "test 3", "master", false)
- project.repository.commit_file(user, file_path_2, "template_test", "test 1", "master", false)
- project.repository.commit_file(user, file_path_3, "feature_proposal", "test 2", "master", false)
+
+ let(:project) do
+ create(:project,
+ :repository,
+ create_template: {
+ user: user,
+ access: Gitlab::Access::MASTER,
+ path: 'issue_templates'
+ })
end
describe '.all' do
diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb
index ddf68c4cf78..77dd3079e22 100644
--- a/spec/lib/gitlab/template/merge_request_template_spec.rb
+++ b/spec/lib/gitlab/template/merge_request_template_spec.rb
@@ -4,16 +4,15 @@ describe Gitlab::Template::MergeRequestTemplate do
subject { described_class }
let(:user) { create(:user) }
- let(:project) { create(:project) }
- let(:file_path_1) { '.gitlab/merge_request_templates/bug.md' }
- let(:file_path_2) { '.gitlab/merge_request_templates/template_test.md' }
- let(:file_path_3) { '.gitlab/merge_request_templates/feature_proposal.md' }
-
- before do
- project.add_user(user, Gitlab::Access::MASTER)
- project.repository.commit_file(user, file_path_1, "something valid", "test 3", "master", false)
- project.repository.commit_file(user, file_path_2, "template_test", "test 1", "master", false)
- project.repository.commit_file(user, file_path_3, "feature_proposal", "test 2", "master", false)
+
+ let(:project) do
+ create(:project,
+ :repository,
+ create_template: {
+ user: user,
+ access: Gitlab::Access::MASTER,
+ path: 'merge_request_templates'
+ })
end
describe '.all' do
diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb
deleted file mode 100644
index 7a140518dd2..00000000000
--- a/spec/lib/gitlab/themes_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require 'spec_helper'
-
-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
-
- expect(css).to include('ui_graphite')
- expect(css).to include(' ui_charcoal ')
- expect(css).to include(' ui_blue')
- end
- end
-
- describe '.by_id' do
- it 'returns a Theme by its ID' do
- expect(described_class.by_id(1).name).to eq 'Graphite'
- expect(described_class.by_id(6).name).to eq 'Blue'
- end
- end
-
- describe '.default' do
- it 'returns the default application theme' do
- allow(described_class).to receive(:default_id).and_return(2)
- expect(described_class.default.id).to eq 2
- end
-
- it 'prevents an infinite loop when configuration default is invalid' do
- default = described_class::APPLICATION_DEFAULT
- themes = described_class::THEMES
-
- config = double(default_theme: 0).as_null_object
- allow(Gitlab).to receive(:config).and_return(config)
- expect(described_class.default.id).to eq default
-
- config = double(default_theme: themes.size + 5).as_null_object
- allow(Gitlab).to receive(:config).and_return(config)
- expect(described_class.default.id).to eq default
- end
- end
-
- describe '.each' do
- it 'passes the block to the THEMES Array' do
- ids = []
- described_class.each { |theme| ids << theme.id }
- expect(ids).not_to be_empty
- end
- end
-end
diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb
index edadab043d7..fcfd8d58b70 100644
--- a/spec/lib/gitlab/upgrader_spec.rb
+++ b/spec/lib/gitlab/upgrader_spec.rb
@@ -32,7 +32,8 @@ describe Gitlab::Upgrader, lib: true do
'43af3e65a486a9237f29f56d96c3b3da59c24ae0 refs/tags/v7.11.2',
'dac18e7728013a77410e926a1e64225703754a2d refs/tags/v7.11.2^{}',
'0bf21fd4b46c980c26fd8c90a14b86a4d90cc950 refs/tags/v7.9.4',
- 'b10de29edbaff7219547dc506cb1468ee35065c3 refs/tags/v7.9.4^{}'])
+ 'b10de29edbaff7219547dc506cb1468ee35065c3 refs/tags/v7.9.4^{}'
+ ])
expect(upgrader.latest_version_raw).to eq("v7.11.2")
end
end
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
new file mode 100644
index 00000000000..a504d299307
--- /dev/null
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Gitlab::UrlBlocker, lib: true do
+ describe '#blocked_url?' do
+ it 'allows imports from configured web host and port' do
+ import_url = "http://#{Gitlab.config.gitlab.host}:#{Gitlab.config.gitlab.port}/t.git"
+ expect(described_class.blocked_url?(import_url)).to be false
+ end
+
+ it 'allows imports from configured SSH host and port' do
+ import_url = "http://#{Gitlab.config.gitlab_shell.ssh_host}:#{Gitlab.config.gitlab_shell.ssh_port}/t.git"
+ expect(described_class.blocked_url?(import_url)).to be false
+ end
+
+ it 'returns true for bad localhost hostname' do
+ expect(described_class.blocked_url?('https://localhost:65535/foo/foo.git')).to be true
+ end
+
+ it 'returns true for bad port' do
+ expect(described_class.blocked_url?('https://gitlab.com:25/foo/foo.git')).to be true
+ end
+
+ it 'returns true for invalid URL' do
+ expect(described_class.blocked_url?('http://:8080')).to be true
+ end
+
+ it 'returns false for legitimate URL' do
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git')).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index a826b24419a..3fe8cf43934 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -99,7 +99,7 @@ describe Gitlab::UrlBuilder, lib: true do
context 'on another object' do
it 'returns a proper URL' do
- project = build_stubbed(:project)
+ project = build_stubbed(:empty_project)
expect { described_class.build(project) }.
to raise_error(NotImplementedError, 'No URL builder defined for Project')
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 2cb74629da8..fc144a2556a 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -5,6 +5,7 @@ describe Gitlab::UrlSanitizer, lib: true do
let(:url_sanitizer) do
described_class.new("https://github.com/me/project.git", credentials: credentials)
end
+ let(:user) { double(:user, username: 'john.doe') }
describe '.sanitize' do
def sanitize_url(url)
@@ -53,12 +54,33 @@ describe Gitlab::UrlSanitizer, lib: true do
end
end
+ describe '.valid?' do
+ it 'validates url strings' do
+ expect(described_class.valid?(nil)).to be(false)
+ expect(described_class.valid?('valid@project:url.git')).to be(true)
+ expect(described_class.valid?('123://invalid:url')).to be(false)
+ end
+ end
+
+ describe '.http_credentials_for_user' do
+ it { expect(described_class.http_credentials_for_user(user)).to eq({ user: 'john.doe' }) }
+ it { expect(described_class.http_credentials_for_user('foo')).to eq({}) }
+ end
+
describe '#sanitized_url' do
it { expect(url_sanitizer.sanitized_url).to eq("https://github.com/me/project.git") }
end
describe '#credentials' do
it { expect(url_sanitizer.credentials).to eq(credentials) }
+
+ context 'when user is given to #initialize' do
+ let(:url_sanitizer) do
+ described_class.new("https://github.com/me/project.git", credentials: described_class.http_credentials_for_user(user))
+ end
+
+ it { expect(url_sanitizer.credentials).to eq({ user: 'john.doe' }) }
+ end
end
describe '#full_url' do
@@ -69,5 +91,13 @@ describe Gitlab::UrlSanitizer, lib: true do
expect(sanitizer.full_url).to eq('user@server:project.git')
end
+
+ context 'when user is given to #initialize' do
+ let(:url_sanitizer) do
+ described_class.new("https://github.com/me/project.git", credentials: described_class.http_credentials_for_user(user))
+ end
+
+ it { expect(url_sanitizer.full_url).to eq("https://john.doe@github.com/me/project.git") }
+ end
end
end
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index d3c3b800b94..369e55f61f1 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -66,7 +66,8 @@ describe Gitlab::UserAccess, lib: true do
end
describe 'push to protected branch' do
- let(:branch) { create :protected_branch, project: project }
+ let(:branch) { create :protected_branch, project: project, name: "test" }
+ let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project }
it 'returns true if user is a master' do
project.team << [user, :master]
@@ -85,6 +86,12 @@ describe Gitlab::UserAccess, lib: true do
expect(access.can_push_to_branch?(branch.name)).to be_falsey
end
+
+ it 'returns true if branch does not exist and user has permission to merge' do
+ project.team << [user, :developer]
+
+ expect(access.can_push_to_branch?(not_existing_branch.name)).to be_truthy
+ end
end
describe 'push to protected branch if allowed for developers' do
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index d5d87310874..56772409989 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -1,7 +1,5 @@
describe Gitlab::Utils, lib: true do
- def to_boolean(value)
- described_class.to_boolean(value)
- end
+ delegate :to_boolean, to: :described_class
describe '.to_boolean' do
it 'accepts booleans' do
diff --git a/spec/lib/gitlab/view/presenter/delegated_spec.rb b/spec/lib/gitlab/view/presenter/delegated_spec.rb
index 888ab80cad5..e9d4af54389 100644
--- a/spec/lib/gitlab/view/presenter/delegated_spec.rb
+++ b/spec/lib/gitlab/view/presenter/delegated_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::View::Presenter::Delegated do
- let(:project) { double(:project, bar: 'baz') }
+ let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do
Class.new(described_class)
end
@@ -12,10 +12,14 @@ describe Gitlab::View::Presenter::Delegated do
describe '#initialize' do
it 'takes arbitrary key/values and exposes them' do
- presenter = presenter_class.new(project, user: 'user', foo: 'bar')
+ presenter = presenter_class.new(project, current_user: 'Jane Doe')
- expect(presenter.user).to eq('user')
- expect(presenter.foo).to eq('bar')
+ expect(presenter.current_user).to eq('Jane Doe')
+ end
+
+ it 'raise an error if the presentee already respond to method' do
+ expect { presenter_class.new(project, user: 'Jane Doe') }.
+ to raise_error Gitlab::View::Presenter::CannotOverrideMethodError
end
end
@@ -23,7 +27,7 @@ describe Gitlab::View::Presenter::Delegated do
it 'forwards missing methods to subject' do
presenter = presenter_class.new(project)
- expect(presenter.bar).to eq('baz')
+ expect(presenter.user).to eq('John Doe')
end
end
end
diff --git a/spec/lib/gitlab/view/presenter/factory_spec.rb b/spec/lib/gitlab/view/presenter/factory_spec.rb
index 55c5ecbf92f..70d2e22b48f 100644
--- a/spec/lib/gitlab/view/presenter/factory_spec.rb
+++ b/spec/lib/gitlab/view/presenter/factory_spec.rb
@@ -22,13 +22,6 @@ describe Gitlab::View::Presenter::Factory do
end
describe '#fabricate!' do
- it 'exposes given params' do
- presenter = described_class.new(build, user: 'user', foo: 'bar').fabricate!
-
- expect(presenter.user).to eq('user')
- expect(presenter.foo).to eq('bar')
- end
-
it 'detects the presenter based on the given subject' do
presenter = described_class.new(build).fabricate!
diff --git a/spec/lib/gitlab/view/presenter/simple_spec.rb b/spec/lib/gitlab/view/presenter/simple_spec.rb
index b489bdf1981..1795ed2405b 100644
--- a/spec/lib/gitlab/view/presenter/simple_spec.rb
+++ b/spec/lib/gitlab/view/presenter/simple_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::View::Presenter::Simple do
- let(:project) { double(:project) }
+ let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do
Class.new(described_class)
end
@@ -12,10 +12,15 @@ describe Gitlab::View::Presenter::Simple do
describe '#initialize' do
it 'takes arbitrary key/values and exposes them' do
- presenter = presenter_class.new(project, user: 'user', foo: 'bar')
+ presenter = presenter_class.new(project, current_user: 'Jane Doe')
- expect(presenter.user).to eq('user')
- expect(presenter.foo).to eq('bar')
+ expect(presenter.current_user).to eq('Jane Doe')
+ end
+
+ it 'override the presentee attributes' do
+ presenter = presenter_class.new(project, user: 'Jane Doe')
+
+ expect(presenter.user).to eq('Jane Doe')
end
end
@@ -23,7 +28,7 @@ describe Gitlab::View::Presenter::Simple do
it 'does not forward missing methods to subject' do
presenter = presenter_class.new(project)
- expect { presenter.foo }.to raise_error(NoMethodError)
+ expect { presenter.user }.to raise_error(NoMethodError)
end
end
end
diff --git a/spec/lib/gitlab/visibility_level_spec.rb b/spec/lib/gitlab/visibility_level_spec.rb
new file mode 100644
index 00000000000..3255c6f1ef7
--- /dev/null
+++ b/spec/lib/gitlab/visibility_level_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::VisibilityLevel, lib: true do
+ describe '.level_value' do
+ it 'converts "public" to integer value' do
+ expect(described_class.level_value('public')).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ it 'converts string integer to integer value' do
+ expect(described_class.level_value('20')).to eq(20)
+ end
+
+ it 'defaults to PRIVATE when string value is not valid' do
+ expect(described_class.level_value('invalid')).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'defaults to PRIVATE when integer value is not valid' do
+ expect(described_class.level_value(100)).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 4b1cd466677..3bd2a3238fe 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::Workhorse, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
def decode_workhorse_header(array)
@@ -42,7 +42,8 @@ describe Gitlab::Workhorse, lib: true do
out = {
subprotocols: ['foo'],
url: 'wss://example.com/terminal.ws',
- headers: { 'Authorization' => ['Token x'] }
+ headers: { 'Authorization' => ['Token x'] },
+ max_session_time: 600
}
out[:ca_pem] = ca_pem if ca_pem
out
@@ -53,7 +54,8 @@ describe Gitlab::Workhorse, lib: true do
'Terminal' => {
'Subprotocols' => ['foo'],
'Url' => 'wss://example.com/terminal.ws',
- 'Header' => { 'Authorization' => ['Token x'] }
+ 'Header' => { 'Authorization' => ['Token x'] },
+ 'MaxSessionTime' => 600
}
}
out['Terminal']['CAPem'] = ca_pem if ca_pem
@@ -177,23 +179,123 @@ describe Gitlab::Workhorse, lib: true do
describe '.git_http_ok' do
let(:user) { create(:user) }
+ let(:repo_path) { repository.path_to_repo }
+ let(:action) { 'info_refs' }
- subject { described_class.git_http_ok(repository, user) }
+ subject { described_class.git_http_ok(repository, user, action) }
- it { expect(subject).to eq({ GL_ID: "user-#{user.id}", RepoPath: repository.path_to_repo }) }
+ it { expect(subject).to include({ GL_ID: "user-#{user.id}", RepoPath: repo_path }) }
- context 'when Gitaly socket path is present' do
- let(:gitaly_socket_path) { '/tmp/gitaly.sock' }
+ context 'when Gitaly is enabled' do
+ let(:gitaly_params) do
+ {
+ GitalySocketPath: URI(Gitlab::GitalyClient.get_address('default')).path,
+ }
+ end
+
+ before do
+ allow(Gitlab.config.gitaly).to receive(:enabled).and_return(true)
+ end
+
+ it 'includes a Repository param' do
+ repo_param = { Repository: {
+ path: repo_path,
+ storage_name: 'default',
+ relative_path: project.full_path + '.git',
+ } }
+
+ expect(subject).to include(repo_param)
+ end
+
+ {
+ git_receive_pack: :post_receive_pack,
+ git_upload_pack: :post_upload_pack
+ }.each do |action_name, feature_flag|
+ context "when #{action_name} action is passed" do
+ let(:action) { action_name }
+
+ context 'when action is enabled by feature flag' do
+ it 'includes Gitaly params in the returned value' do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag).and_return(true)
+
+ expect(subject).to include(gitaly_params)
+ end
+ end
+
+ context 'when action is not enabled by feature flag' do
+ it 'does not include Gitaly params in the returned value' do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag).and_return(false)
+
+ expect(subject).not_to include(gitaly_params)
+ end
+ end
+ end
+ end
+
+ context "when info_refs action is passed" do
+ let(:action) { 'info_refs' }
+
+ it { expect(subject).to include(gitaly_params) }
+ end
+
+ context 'when action passed is not supported by Gitaly' do
+ let(:action) { 'download' }
+
+ it { expect { subject }.to raise_exception('Unsupported action: download') }
+ end
+ end
+ end
+
+ describe '.set_key_and_notify' do
+ let(:key) { 'test-key' }
+ let(:value) { 'test-value' }
+
+ subject { described_class.set_key_and_notify(key, value, overwrite: overwrite) }
+
+ shared_examples 'set and notify' do
+ it 'set and return the same value' do
+ is_expected.to eq(value)
+ end
+
+ it 'set and notify' do
+ expect_any_instance_of(Redis).to receive(:publish)
+ .with(described_class::NOTIFICATION_CHANNEL, "test-key=test-value")
+
+ subject
+ end
+ end
+
+ context 'when we set a new key' do
+ let(:overwrite) { true }
+
+ it_behaves_like 'set and notify'
+ end
+
+ context 'when we set an existing key' do
+ let(:old_value) { 'existing-key' }
before do
- allow(Gitlab.config.gitaly).to receive(:socket_path).and_return(gitaly_socket_path)
+ described_class.set_key_and_notify(key, old_value, overwrite: true)
end
- it 'includes Gitaly params in the returned value' do
- expect(subject).to include({
- GitalyResourcePath: "/projects/#{repository.project.id}/git-http/info-refs",
- GitalySocketPath: gitaly_socket_path,
- })
+ context 'and overwrite' do
+ let(:overwrite) { true }
+
+ it_behaves_like 'set and notify'
+ end
+
+ context 'and do not overwrite' do
+ let(:overwrite) { false }
+
+ it 'try to set but return the previous value' do
+ is_expected.to eq(old_value)
+ end
+
+ it 'does not notify' do
+ expect_any_instance_of(Redis).not_to receive(:publish)
+
+ subject
+ end
end
end
end
diff --git a/spec/lib/light_url_builder_spec.rb b/spec/lib/light_url_builder_spec.rb
index a826b24419a..3fe8cf43934 100644
--- a/spec/lib/light_url_builder_spec.rb
+++ b/spec/lib/light_url_builder_spec.rb
@@ -99,7 +99,7 @@ describe Gitlab::UrlBuilder, lib: true do
context 'on another object' do
it 'returns a proper URL' do
- project = build_stubbed(:project)
+ project = build_stubbed(:empty_project)
expect { described_class.build(project) }.
to raise_error(NotImplementedError, 'No URL builder defined for Project')
diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb
index 5ccf1100898..4b5938edeb9 100644
--- a/spec/lib/mattermost/command_spec.rb
+++ b/spec/lib/mattermost/command_spec.rb
@@ -13,8 +13,7 @@ describe Mattermost::Command do
describe '#create' do
let(:params) do
{ team_id: 'abc',
- trigger: 'gitlab'
- }
+ trigger: 'gitlab' }
end
subject { described_class.new(nil).create(params) }
@@ -24,7 +23,8 @@ describe Mattermost::Command do
stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create').
with(body: {
team_id: 'abc',
- trigger: 'gitlab' }.to_json).
+ trigger: 'gitlab'
+ }.to_json).
to_return(
status: 200,
headers: { 'Content-Type' => 'application/json' },
diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb
index 2d14be6bcc2..ac493fdb20f 100644
--- a/spec/lib/mattermost/team_spec.rb
+++ b/spec/lib/mattermost/team_spec.rb
@@ -13,19 +13,20 @@ describe Mattermost::Team do
context 'for valid request' do
let(:response) do
- [{
- "id" => "xiyro8huptfhdndadpz8r3wnbo",
- "create_at" => 1482174222155,
- "update_at" => 1482174222155,
- "delete_at" => 0,
- "display_name" => "chatops",
- "name" => "chatops",
- "email" => "admin@example.com",
- "type" => "O",
- "company_name" => "",
- "allowed_domains" => "",
- "invite_id" => "o4utakb9jtb7imctdfzbf9r5ro",
- "allow_open_invite" => false }]
+ { "xiyro8huptfhdndadpz8r3wnbo" => {
+ "id" => "xiyro8huptfhdndadpz8r3wnbo",
+ "create_at" => 1482174222155,
+ "update_at" => 1482174222155,
+ "delete_at" => 0,
+ "display_name" => "chatops",
+ "name" => "chatops",
+ "email" => "admin@example.com",
+ "type" => "O",
+ "company_name" => "",
+ "allowed_domains" => "",
+ "invite_id" => "o4utakb9jtb7imctdfzbf9r5ro",
+ "allow_open_invite" => false
+ } }
end
before do
@@ -38,7 +39,7 @@ describe Mattermost::Team do
end
it 'returns a token' do
- is_expected.to eq(response)
+ is_expected.to eq(response.values)
end
end
diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb
index f227926f39c..5892f3481a4 100644
--- a/spec/lib/repository_cache_spec.rb
+++ b/spec/lib/repository_cache_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe RepositoryCache, lib: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:backend) { double('backend').as_null_object }
let(:cache) { RepositoryCache.new('example', project.id, backend) }