summaryrefslogtreecommitdiff
path: root/spec/lib
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib')
-rw-r--r--spec/lib/api/helpers_spec.rb42
-rw-r--r--spec/lib/backup/files_spec.rb14
-rw-r--r--spec/lib/backup/repository_spec.rb12
-rw-r--r--spec/lib/banzai/commit_renderer_spec.rb5
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb10
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb16
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb47
-rw-r--r--spec/lib/banzai/filter/commit_trailers_filter_spec.rb40
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb22
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb12
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb6
-rw-r--r--spec/lib/banzai/issuable_extractor_spec.rb2
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb11
-rw-r--r--spec/lib/banzai/redactor_spec.rb4
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb18
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb16
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/issue_parser_spec.rb25
-rw-r--r--spec/lib/banzai/reference_parser/label_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/merge_request_parser_spec.rb30
-rw-r--r--spec/lib/banzai/reference_parser/milestone_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/snippet_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb2
-rw-r--r--spec/lib/banzai/render_context_spec.rb37
-rw-r--r--spec/lib/forever_spec.rb21
-rw-r--r--spec/lib/gitlab/auth/ldap/user_spec.rb8
-rw-r--r--spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb62
-rw-r--r--spec/lib/gitlab/auth/saml/identity_linker_spec.rb48
-rw-r--r--spec/lib/gitlab/auth_spec.rb122
-rw-r--r--spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb35
-rw-r--r--spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb31
-rw-r--r--spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb31
-rw-r--r--spec/lib/gitlab/bare_repository_import/importer_spec.rb21
-rw-r--r--spec/lib/gitlab/bare_repository_import/repository_spec.rb2
-rw-r--r--spec/lib/gitlab/bitbucket_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/status/build/action_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/status/build/canceled_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/build/created_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/build/erased_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb62
-rw-r--r--spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/status/build/failed_spec.rb83
-rw-r--r--spec/lib/gitlab/ci/status/build/manual_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/status/build/pending_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/build/play_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/status/build/retried_spec.rb96
-rw-r--r--spec/lib/gitlab/ci/status/build/retryable_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/status/build/skipped_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/build/stop_spec.rb24
-rw-r--r--spec/lib/gitlab/ci/status/success_warning_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/trace_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/variables/collection/item_spec.rb35
-rw-r--r--spec/lib/gitlab/data_builder/note_spec.rb8
-rw-r--r--spec/lib/gitlab/database/sha_attribute_spec.rb8
-rw-r--r--spec/lib/gitlab/diff/highlight_spec.rb9
-rw-r--r--spec/lib/gitlab/email/handler_spec.rb30
-rw-r--r--spec/lib/gitlab/git/attributes_parser_spec.rb12
-rw-r--r--spec/lib/gitlab/git/checksum_spec.rb38
-rw-r--r--spec/lib/gitlab/git/committer_with_hooks_spec.rb154
-rw-r--r--spec/lib/gitlab/git/info_attributes_spec.rb43
-rw-r--r--spec/lib/gitlab/git/raw_diff_change_spec.rb66
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb216
-rw-r--r--spec/lib/gitlab/git/wiki_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_spec.rb100
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb8
-rw-r--r--spec/lib/gitlab/gitaly_client/repository_service_spec.rb43
-rw-r--r--spec/lib/gitlab/gitlab_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/google_code_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml8
-rw-r--r--spec/lib/gitlab/import_export/importer_spec.rb104
-rw-r--r--spec/lib/gitlab/import_export/lfs_restorer_spec.rb75
-rw-r--r--spec/lib/gitlab/import_export/lfs_saver_spec.rb62
-rw-r--r--spec/lib/gitlab/import_export/project.json61
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb22
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb5
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml11
-rw-r--r--spec/lib/gitlab/import_export/wiki_restorer_spec.rb4
-rw-r--r--spec/lib/gitlab/kubernetes/helm/base_command_spec.rb18
-rw-r--r--spec/lib/gitlab/kubernetes/helm/init_command_spec.rb20
-rw-r--r--spec/lib/gitlab/kubernetes/helm/install_command_spec.rb66
-rw-r--r--spec/lib/gitlab/legacy_github_import/project_creator_spec.rb2
-rw-r--r--spec/lib/gitlab/pages_client_spec.rb172
-rw-r--r--spec/lib/gitlab/sentry_spec.rb44
-rw-r--r--spec/lib/gitlab/shell_spec.rb54
-rw-r--r--spec/lib/gitlab/user_access_spec.rb12
-rw-r--r--spec/lib/gitlab/utils_spec.rb11
-rw-r--r--spec/lib/gitlab/view/presenter/base_spec.rb7
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb26
-rw-r--r--spec/lib/gitlab_spec.rb16
-rw-r--r--spec/lib/omni_auth/strategies/jwt_spec.rb87
-rw-r--r--spec/lib/rspec_flaky/config_spec.rb30
-rw-r--r--spec/lib/rspec_flaky/flaky_examples_collection_spec.rb14
-rw-r--r--spec/lib/rspec_flaky/listener_spec.rb114
-rw-r--r--spec/lib/rspec_flaky/report_spec.rb125
-rw-r--r--spec/lib/uploaded_file_spec.rb116
102 files changed, 2905 insertions, 516 deletions
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 3c4deba4712..58a49124ce6 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -3,6 +3,48 @@ require 'spec_helper'
describe API::Helpers do
subject { Class.new.include(described_class).new }
+ describe '#find_project' do
+ let(:project) { create(:project) }
+
+ shared_examples 'project finder' do
+ context 'when project exists' do
+ it 'returns requested project' do
+ expect(subject.find_project(existing_id)).to eq(project)
+ end
+
+ it 'returns nil' do
+ expect(subject.find_project(non_existing_id)).to be_nil
+ end
+ end
+ end
+
+ context 'when ID is used as an argument' do
+ let(:existing_id) { project.id }
+ let(:non_existing_id) { (Project.maximum(:id) || 0) + 1 }
+
+ it_behaves_like 'project finder'
+ end
+
+ context 'when PATH is used as an argument' do
+ let(:existing_id) { project.full_path }
+ let(:non_existing_id) { 'something/else' }
+
+ it_behaves_like 'project finder'
+
+ context 'with an invalid PATH' do
+ let(:non_existing_id) { 'undefined' } # path without slash
+
+ it_behaves_like 'project finder'
+
+ it 'does not hit the database' do
+ expect(Project).not_to receive(:find_by_full_path)
+
+ subject.find_project(non_existing_id)
+ end
+ end
+ end
+ end
+
describe '#find_namespace' do
let(:namespace) { create(:namespace) }
diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb
index 14d055cbcc1..99872211a4e 100644
--- a/spec/lib/backup/files_spec.rb
+++ b/spec/lib/backup/files_spec.rb
@@ -62,5 +62,19 @@ describe Backup::Files do
subject.restore
end
end
+
+ describe 'folders that are a mountpoint' do
+ before do
+ allow(FileUtils).to receive(:mv).and_raise(Errno::EBUSY)
+ allow(subject).to receive(:run_pipeline!).and_return(true)
+ end
+
+ it 'shows error message' do
+ expect(subject).to receive(:resource_busy_error).with("/var/gitlab-registry")
+ .and_call_original
+
+ expect { subject.restore }.to raise_error(/is a mountpoint/)
+ end
+ end
end
end
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index e4c1c9bafc0..b3777be312b 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -81,6 +81,18 @@ describe Backup::Repository do
subject.restore
end
end
+
+ describe 'folder that is a mountpoint' do
+ before do
+ allow(FileUtils).to receive(:mv).and_raise(Errno::EBUSY)
+ end
+
+ it 'shows error message' do
+ expect(subject).to receive(:resource_busy_error).and_call_original
+
+ expect { subject.restore }.to raise_error(/is a mountpoint/)
+ end
+ end
end
describe '#empty_repo?' do
diff --git a/spec/lib/banzai/commit_renderer_spec.rb b/spec/lib/banzai/commit_renderer_spec.rb
index e7ebb2a332f..1f53657c59c 100644
--- a/spec/lib/banzai/commit_renderer_spec.rb
+++ b/spec/lib/banzai/commit_renderer_spec.rb
@@ -6,7 +6,10 @@ describe Banzai::CommitRenderer do
user = build(:user)
project = create(:project, :repository)
- expect(Banzai::ObjectRenderer).to receive(:new).with(project, user).and_call_original
+ expect(Banzai::ObjectRenderer)
+ .to receive(:new)
+ .with(user: user, default_project: project)
+ .and_call_original
described_class::ATTRIBUTES.each do |attr|
expect_any_instance_of(Banzai::ObjectRenderer).to receive(:render).with([project.commit], attr).once.and_call_original
diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
index 68ca960caab..aadfe7637dd 100644
--- a/spec/lib/banzai/cross_project_reference_spec.rb
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -14,6 +14,16 @@ describe Banzai::CrossProjectReference do
end
end
+ context 'when no project was referenced in group context' do
+ it 'returns the group from context' do
+ group = double
+
+ allow(self).to receive(:context).and_return({ group: group })
+
+ expect(parent_from_ref(nil)).to eq group
+ end
+ end
+
context 'when referenced project does not exist' do
it 'returns nil' do
expect(parent_from_ref('invalid/reference')).to be_nil
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 a41a28a56f1..e1af5a15371 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -233,4 +233,20 @@ describe Banzai::Filter::CommitRangeReferenceFilter do
expect(reference_filter(act).to_html).to eq exp
end
end
+
+ context 'group context' do
+ let(:context) { { project: nil, group: create(:group) } }
+
+ it 'ignores internal references' do
+ exp = act = "See #{range.to_reference}"
+
+ expect(reference_filter(act, context).to_html).to eq exp
+ end
+
+ it 'links to a full-path reference' do
+ reference = "#{project.full_path}@#{commit1.short_id}...#{commit2.short_id}"
+
+ expect(reference_filter("See #{reference}", context).css('a').first.text).to eql(reference)
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index 35f8792ff35..d6c9e9e4b19 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -207,4 +207,51 @@ describe Banzai::Filter::CommitReferenceFilter do
expect(reference_filter(act).to_html).to match(%r{<a.+>#{Regexp.escape(invalidate_reference(reference))}</a>})
end
end
+
+ context 'URL reference for a commit patch' do
+ let(:namespace) { create(:namespace) }
+ let(:project2) { create(:project, :public, :repository, namespace: namespace) }
+ let(:commit) { project2.commit }
+ let(:link) { urls.project_commit_url(project2, commit.id) }
+ let(:extension) { '.patch' }
+ let(:reference) { link + extension }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href'))
+ .to eq reference
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.text).to eq("See #{commit.reference_link_text(project)} (patch)")
+ end
+
+ it 'does not link to patch when extension match is after the path' do
+ invalidate_commit_reference = reference_filter("#{link}/builds.patch")
+
+ doc = reference_filter("See (#{invalidate_commit_reference})")
+
+ expect(doc.css('a').first.attr('href')).to eq "#{link}/builds"
+ expect(doc.text).to eq("See (#{commit.reference_link_text(project)} (builds).patch)")
+ end
+ end
+
+ context 'group context' do
+ let(:context) { { project: nil, group: create(:group) } }
+
+ it 'ignores internal references' do
+ exp = act = "See #{commit.id}"
+
+ expect(reference_filter(act, context).to_html).to eq exp
+ end
+
+ it 'links to a valid reference' do
+ act = "See #{project.full_path}@#{commit.id}"
+
+ expect(reference_filter(act, context).css('a').first.text).to eql("#{project.full_path}@#{commit.short_id}")
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/commit_trailers_filter_spec.rb b/spec/lib/banzai/filter/commit_trailers_filter_spec.rb
index 1fd145116df..068cdc85a07 100644
--- a/spec/lib/banzai/filter/commit_trailers_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_trailers_filter_spec.rb
@@ -47,16 +47,36 @@ describe Banzai::Filter::CommitTrailersFilter do
)
end
- it 'non GitLab users and replaces them with mailto links' do
- _, message_html = build_commit_message(
- trailer: trailer,
- name: FFaker::Name.name,
- email: email
- )
+ context 'non GitLab users' do
+ shared_examples 'mailto links' do
+ it 'replaces them with mailto links' do
+ _, message_html = build_commit_message(
+ trailer: trailer,
+ name: FFaker::Name.name,
+ email: email
+ )
- doc = filter(message_html)
+ doc = filter(message_html)
- expect_to_have_mailto_link(doc, email: email, trailer: trailer)
+ expect_to_have_mailto_link_with_avatar(doc, email: email, trailer: trailer)
+ end
+ end
+
+ context 'when Gravatar is disabled' do
+ before do
+ stub_application_setting(gravatar_enabled: false)
+ end
+
+ it_behaves_like 'mailto links'
+ end
+
+ context 'when Gravatar is enabled' do
+ before do
+ stub_application_setting(gravatar_enabled: true)
+ end
+
+ it_behaves_like 'mailto links'
+ end
end
it 'multiple trailers in the same message' do
@@ -69,7 +89,7 @@ describe Banzai::Filter::CommitTrailersFilter do
doc = filter(message)
expect_to_have_user_link_with_avatar(doc, user: user, trailer: trailer)
- expect_to_have_mailto_link(doc, email: email, trailer: different_trailer)
+ expect_to_have_mailto_link_with_avatar(doc, email: email, trailer: different_trailer)
end
context 'special names' do
@@ -90,7 +110,7 @@ describe Banzai::Filter::CommitTrailersFilter do
doc = filter(message_html)
- expect_to_have_mailto_link(doc, email: email, trailer: trailer)
+ expect_to_have_mailto_link_with_avatar(doc, email: email, trailer: trailer)
expect(doc.text).to match Regexp.escape(message)
end
end
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 0c524a1551f..392905076dc 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -596,6 +596,27 @@ describe Banzai::Filter::LabelReferenceFilter do
end
describe 'group context' do
+ it 'points to the page defined in label_url_method' do
+ group = create(:group)
+ label = create(:group_label, group: group)
+ reference = "~#{label.name}"
+
+ result = reference_filter("See #{reference}", { project: nil, group: group, label_url_method: :group_url } )
+
+ expect(result.css('a').first.attr('href')).to eq(urls.group_url(group, label_name: label.name))
+ end
+
+ it 'finds labels also in ancestor groups' do
+ group = create(:group)
+ label = create(:group_label, group: group)
+ subgroup = create(:group, parent: group)
+ reference = "~#{label.name}"
+
+ result = reference_filter("See #{reference}", { project: nil, group: subgroup, label_url_method: :group_url } )
+
+ expect(result.css('a').first.attr('href')).to eq(urls.group_url(subgroup, label_name: label.name))
+ end
+
it 'points to referenced project issues page' do
project = create(:project)
label = create(:label, project: project)
@@ -604,6 +625,7 @@ describe Banzai::Filter::LabelReferenceFilter do
result = reference_filter("See #{reference}", { project: nil, group: create(:group) } )
expect(result.css('a').first.attr('href')).to eq(urls.project_issues_url(project, label_name: label.name))
+ expect(result.css('a').first.text).to eq "#{label.name} in #{project.full_name}"
end
end
end
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 6a9087d2e59..f8fa9b2d13d 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -343,14 +343,22 @@ describe Banzai::Filter::MilestoneReferenceFilter do
end
context 'group context' do
+ let(:context) { { project: nil, group: create(:group) } }
+ let(:milestone) { create(:milestone, project: project) }
+
it 'links to a valid reference' do
- milestone = create(:milestone, project: project)
reference = "#{project.full_path}%#{milestone.iid}"
- result = reference_filter("See #{reference}", { project: nil, group: create(:group) } )
+ result = reference_filter("See #{reference}", context)
expect(result.css('a').first.attr('href')).to eq(urls.milestone_url(milestone))
end
+
+ it 'ignores internal references' do
+ exp = act = "See %#{milestone.iid}"
+
+ expect(reference_filter(act, context).to_html).to eq exp
+ end
end
context 'when milestone is open' do
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index e068e02d4fc..21cf092428d 100644
--- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -210,5 +210,11 @@ describe Banzai::Filter::SnippetReferenceFilter do
expect(result.css('a').first.attr('href')).to eq(urls.project_snippet_url(project, snippet))
end
+
+ it 'ignores internal references' do
+ exp = act = "See $#{snippet.id}"
+
+ expect(reference_filter(act, project: nil, group: create(:group)).to_html).to eq exp
+ end
end
end
diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb
index 69763476dac..f42951d9781 100644
--- a/spec/lib/banzai/issuable_extractor_spec.rb
+++ b/spec/lib/banzai/issuable_extractor_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::IssuableExtractor do
let(:project) { create(:project) }
let(:user) { create(:user) }
- let(:extractor) { described_class.new(project, user) }
+ let(:extractor) { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:issue_link) do
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index 074d521a5c6..209a547c3b3 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -3,8 +3,15 @@ require 'spec_helper'
describe Banzai::ObjectRenderer do
let(:project) { create(:project, :repository) }
let(:user) { project.owner }
- let(:renderer) { described_class.new(project, user, custom_value: 'value') }
- let(:object) { Note.new(note: 'hello', note_html: '<p dir="auto">hello</p>', cached_markdown_version: CacheMarkdownField::CACHE_VERSION) }
+ let(:renderer) do
+ described_class.new(
+ default_project: project,
+ user: user,
+ redaction_context: { custom_value: 'value' }
+ )
+ end
+
+ let(:object) { Note.new(note: 'hello', note_html: '<p dir="auto">hello</p>', cached_markdown_version: CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
describe '#render' do
context 'with cache' do
diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/redactor_spec.rb
index 441f3725985..aaeec953e4b 100644
--- a/spec/lib/banzai/redactor_spec.rb
+++ b/spec/lib/banzai/redactor_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Redactor do
let(:user) { create(:user) }
let(:project) { build(:project) }
- let(:redactor) { described_class.new(project, user) }
+ let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
describe '#redact' do
context 'when reference not visible to user' do
@@ -54,7 +54,7 @@ describe Banzai::Redactor do
context 'when project is in pending delete' do
let!(:issue) { create(:issue, project: project) }
- let(:redactor) { described_class.new(project, user) }
+ let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
before do
project.update(pending_delete: true)
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index 6175d4c4ca9..4e6e8eca38a 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -5,13 +5,14 @@ describe Banzai::ReferenceParser::BaseParser do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
+ let(:context) { Banzai::RenderContext.new(project, user) }
subject do
klass = Class.new(described_class) do
self.reference_type = :foo
end
- klass.new(project, user)
+ klass.new(context)
end
describe '.reference_type=' do
@@ -23,6 +24,19 @@ describe Banzai::ReferenceParser::BaseParser do
end
end
+ describe '#project_for_node' do
+ it 'returns the Project for a node' do
+ document = instance_double('document', fragment?: false)
+ project = instance_double('project')
+ object = instance_double('object', project: project)
+ node = instance_double('node', document: document)
+
+ context.associate_document(document, object)
+
+ expect(subject.project_for_node(node)).to eq(project)
+ end
+ end
+
describe '#nodes_visible_to_user' do
let(:link) { empty_html_link }
@@ -164,7 +178,7 @@ describe Banzai::ReferenceParser::BaseParser do
self.reference_type = :test
end
- instance = dummy.new(project, user)
+ instance = dummy.new(Banzai::RenderContext.new(project, user))
document = Nokogiri::HTML.fragment('<a class="gfm"></a><a class="gfm" data-reference-type="test"></a>')
expect(instance).to receive(:gather_references)
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
index 3505659c2c3..cca53a8b9b9 100644
--- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -5,7 +5,7 @@ describe Banzai::ReferenceParser::CommitParser do
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
index 21813177deb..ff3b82cc482 100644
--- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -5,7 +5,7 @@ describe Banzai::ReferenceParser::CommitRangeParser do
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
@@ -107,12 +107,9 @@ describe Banzai::ReferenceParser::CommitRangeParser do
describe '#find_object' do
let(:range) { double(:range) }
- before do
- expect(CommitRange).to receive(:new).and_return(range)
- end
-
context 'when the range has valid commits' do
it 'returns the commit range' do
+ expect(CommitRange).to receive(:new).and_return(range)
expect(range).to receive(:valid_commits?).and_return(true)
expect(subject.find_object(project, '123..456')).to eq(range)
@@ -121,10 +118,19 @@ describe Banzai::ReferenceParser::CommitRangeParser do
context 'when the range does not have any valid commits' do
it 'returns nil' do
+ expect(CommitRange).to receive(:new).and_return(range)
expect(range).to receive(:valid_commits?).and_return(false)
expect(subject.find_object(project, '123..456')).to be_nil
end
end
+
+ context 'group context' do
+ it 'returns nil' do
+ group = create(:group)
+
+ expect(subject.find_object(group, '123..456')).to be_nil
+ end
+ end
end
end
diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
index 25969b65168..1cb31e57114 100644
--- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -5,7 +5,7 @@ describe Banzai::ReferenceParser::ExternalIssueParser do
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
index 0a63567ee40..77c2064caba 100644
--- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
@@ -7,7 +7,7 @@ describe Banzai::ReferenceParser::IssueParser do
let(:user) { create(:user) }
let(:issue) { create(:issue, project: project) }
let(:link) { empty_html_link }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
@@ -117,4 +117,27 @@ describe Banzai::ReferenceParser::IssueParser do
expect(subject.records_for_nodes(nodes)).to eq({ link => issue })
end
end
+
+ context 'when checking multiple merge requests on another project' do
+ let(:other_project) { create(:project, :public) }
+ let(:other_issue) { create(:issue, project: other_project) }
+
+ let(:control_links) do
+ [issue_link(other_issue)]
+ end
+
+ let(:actual_links) do
+ control_links + [issue_link(create(:issue, project: other_project))]
+ end
+
+ def issue_link(issue)
+ Nokogiri::HTML.fragment(%Q{<a data-issue="#{issue.id}"></a>}).children[0]
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'no N+1 queries'
+ end
end
diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb
index b700161d6c2..e4df2533821 100644
--- a/spec/lib/banzai/reference_parser/label_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb
@@ -6,7 +6,7 @@ describe Banzai::ReferenceParser::LabelParser do
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
let(:label) { create(:label, project: project) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
diff --git a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
index 775749ae3a7..5417b1f00be 100644
--- a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
@@ -4,14 +4,13 @@ describe Banzai::ReferenceParser::MergeRequestParser do
include ReferenceParserHelpers
let(:user) { create(:user) }
- let(:merge_request) { create(:merge_request) }
- subject { described_class.new(merge_request.target_project, user) }
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ subject { described_class.new(Banzai::RenderContext.new(merge_request.target_project, user)) }
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
context 'when the link has a data-issue attribute' do
- let(:project) { merge_request.target_project }
-
before do
project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
link['data-merge-request'] = merge_request.id.to_s
@@ -40,4 +39,27 @@ describe Banzai::ReferenceParser::MergeRequestParser do
end
end
end
+
+ context 'when checking multiple merge requests on another project' do
+ let(:other_project) { create(:project, :public) }
+ let(:other_merge_request) { create(:merge_request, source_project: other_project) }
+
+ let(:control_links) do
+ [merge_request_link(other_merge_request)]
+ end
+
+ let(:actual_links) do
+ control_links + [merge_request_link(create(:merge_request, :conflict, source_project: other_project))]
+ end
+
+ def merge_request_link(merge_request)
+ Nokogiri::HTML.fragment(%Q{<a data-merge-request="#{merge_request.id}"></a>}).children[0]
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'no N+1 queries'
+ end
end
diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
index 7dacdf8d629..751d042ffde 100644
--- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb
@@ -6,7 +6,7 @@ describe Banzai::ReferenceParser::MilestoneParser do
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
let(:milestone) { create(:milestone, project: project) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
index 69ec3f66aa8..d410bd4c164 100644
--- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb
@@ -9,7 +9,7 @@ describe Banzai::ReferenceParser::SnippetParser do
let(:external_user) { create(:user, :external) }
let(:project_member) { create(:user) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
def visible_references(snippet_visibility, user = nil)
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index b079a3be029..112447f098e 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -6,7 +6,7 @@ describe Banzai::ReferenceParser::UserParser do
let(:group) { create(:group) }
let(:user) { create(:user) }
let(:project) { create(:project, :public, group: group, creator: user) }
- subject { described_class.new(project, user) }
+ subject { described_class.new(Banzai::RenderContext.new(project, user)) }
let(:link) { empty_html_link }
describe '#referenced_by' do
diff --git a/spec/lib/banzai/render_context_spec.rb b/spec/lib/banzai/render_context_spec.rb
new file mode 100644
index 00000000000..ad17db11613
--- /dev/null
+++ b/spec/lib/banzai/render_context_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Banzai::RenderContext do
+ let(:document) { Nokogiri::HTML.fragment('<p>hello</p>') }
+
+ describe '#project_for_node' do
+ it 'returns the default project if no associated project was found' do
+ project = instance_double('project')
+ context = described_class.new(project)
+
+ expect(context.project_for_node(document)).to eq(project)
+ end
+
+ it 'returns the associated project if one was associated explicitly' do
+ project = instance_double('project')
+ obj = instance_double('object', project: project)
+ context = described_class.new
+
+ context.associate_document(document, obj)
+
+ expect(context.project_for_node(document)).to eq(project)
+ end
+
+ it 'returns the project associated with a DocumentFragment when using a node' do
+ project = instance_double('project')
+ obj = instance_double('object', project: project)
+ context = described_class.new
+ node = document.children.first
+
+ context.associate_document(document, obj)
+
+ expect(context.project_for_node(node)).to eq(project)
+ end
+ end
+end
diff --git a/spec/lib/forever_spec.rb b/spec/lib/forever_spec.rb
new file mode 100644
index 00000000000..cf40c467c72
--- /dev/null
+++ b/spec/lib/forever_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Forever do
+ describe '.date' do
+ subject { described_class.date }
+
+ context 'when using PostgreSQL' do
+ it 'should return Postgresql future date' do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(true)
+ expect(subject).to eq(described_class::POSTGRESQL_DATE)
+ end
+ end
+
+ context 'when using MySQL' do
+ it 'should return MySQL future date' do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(false)
+ expect(subject).to eq(described_class::MYSQL_DATE)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/auth/ldap/user_spec.rb b/spec/lib/gitlab/auth/ldap/user_spec.rb
index cab2169593a..653c19942ea 100644
--- a/spec/lib/gitlab/auth/ldap/user_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/user_spec.rb
@@ -25,20 +25,20 @@ describe Gitlab::Auth::LDAP::User do
OmniAuth::AuthHash.new(uid: 'uid=John Smith,ou=People,dc=example,dc=com', provider: 'ldapmain', info: info_upper_case)
end
- describe '#changed?' do
+ describe '#should_save?' do
it "marks existing ldap user as changed" do
create(:omniauth_user, extern_uid: 'uid=John Smith,ou=People,dc=example,dc=com', provider: 'ldapmain')
- expect(ldap_user.changed?).to be_truthy
+ expect(ldap_user.should_save?).to be_truthy
end
it "marks existing non-ldap user if the email matches as changed" do
create(:user, email: 'john@example.com')
- expect(ldap_user.changed?).to be_truthy
+ expect(ldap_user.should_save?).to be_truthy
end
it "does not mark existing ldap user as changed" do
create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=john smith,ou=people,dc=example,dc=com', provider: 'ldapmain')
- expect(ldap_user.changed?).to be_falsey
+ expect(ldap_user.should_save?).to be_falsey
end
end
diff --git a/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb b/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb
new file mode 100644
index 00000000000..528f1b4ec57
--- /dev/null
+++ b/spec/lib/gitlab/auth/o_auth/identity_linker_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+
+describe Gitlab::Auth::OAuth::IdentityLinker do
+ let(:user) { create(:user) }
+ let(:provider) { 'twitter' }
+ let(:uid) { user.email }
+ let(:oauth) { { 'provider' => provider, 'uid' => uid } }
+
+ subject { described_class.new(user, oauth) }
+
+ context 'linked identity exists' do
+ let!(:identity) { user.identities.create!(provider: provider, extern_uid: uid) }
+
+ it "doesn't create new identity" do
+ expect { subject.link }.not_to change { Identity.count }
+ end
+
+ it "sets #changed? to false" do
+ subject.link
+
+ expect(subject).not_to be_changed
+ end
+ end
+
+ context 'identity already linked to different user' do
+ let!(:identity) { create(:identity, provider: provider, extern_uid: uid) }
+
+ it "#changed? returns false" do
+ subject.link
+
+ expect(subject).not_to be_changed
+ end
+
+ it 'exposes error message' do
+ expect(subject.error_message).to eq 'Extern uid has already been taken'
+ end
+ end
+
+ context 'identity needs to be created' do
+ it 'creates linked identity' do
+ expect { subject.link }.to change { user.identities.count }
+ end
+
+ it 'sets identity provider' do
+ subject.link
+
+ expect(user.identities.last.provider).to eq provider
+ end
+
+ it 'sets identity extern_uid' do
+ subject.link
+
+ expect(user.identities.last.extern_uid).to eq uid
+ end
+
+ it 'sets #changed? to true' do
+ subject.link
+
+ expect(subject).to be_changed
+ end
+ end
+end
diff --git a/spec/lib/gitlab/auth/saml/identity_linker_spec.rb b/spec/lib/gitlab/auth/saml/identity_linker_spec.rb
new file mode 100644
index 00000000000..f3305d574cc
--- /dev/null
+++ b/spec/lib/gitlab/auth/saml/identity_linker_spec.rb
@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+describe Gitlab::Auth::Saml::IdentityLinker do
+ let(:user) { create(:user) }
+ let(:provider) { 'saml' }
+ let(:uid) { user.email }
+ let(:oauth) { { 'provider' => provider, 'uid' => uid } }
+
+ subject { described_class.new(user, oauth) }
+
+ context 'linked identity exists' do
+ let!(:identity) { user.identities.create!(provider: provider, extern_uid: uid) }
+
+ it "doesn't create new identity" do
+ expect { subject.link }.not_to change { Identity.count }
+ end
+
+ it "sets #changed? to false" do
+ subject.link
+
+ expect(subject).not_to be_changed
+ end
+ end
+
+ context 'identity needs to be created' do
+ it 'creates linked identity' do
+ expect { subject.link }.to change { user.identities.count }
+ end
+
+ it 'sets identity provider' do
+ subject.link
+
+ expect(user.identities.last.provider).to eq provider
+ end
+
+ it 'sets identity extern_uid' do
+ subject.link
+
+ expect(user.identities.last.extern_uid).to eq uid
+ end
+
+ it 'sets #changed? to true' do
+ subject.link
+
+ expect(subject).to be_changed
+ end
+ end
+end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 18cef8ec996..9ccd0b206cc 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::Auth do
describe 'constants' do
it 'API_SCOPES contains all scopes for API access' do
- expect(subject::API_SCOPES).to eq %i[api read_user sudo]
+ expect(subject::API_SCOPES).to eq %i[api read_user sudo read_repository]
end
it 'OPENID_SCOPES contains all scopes for OpenID Connect' do
@@ -19,7 +19,7 @@ describe Gitlab::Auth do
it 'optional_scopes contains all non-default scopes' do
stub_container_registry_config(enabled: true)
- expect(subject.optional_scopes).to eq %i[read_user sudo read_registry openid]
+ expect(subject.optional_scopes).to eq %i[read_user sudo read_repository read_registry openid]
end
context 'registry_scopes' do
@@ -231,7 +231,7 @@ describe Gitlab::Auth do
.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
+ it 'fails through oauth authentication when the username is oauth2' do
user = create(
:user,
username: 'oauth2',
@@ -255,6 +255,122 @@ describe Gitlab::Auth do
expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalAccessTokenError)
end
+
+ context 'while using deploy tokens' do
+ let(:project) { create(:project) }
+ let(:auth_failure) { Gitlab::Auth::Result.new(nil, nil) }
+
+ context 'when the deploy token has read_repository as scope' do
+ let(:deploy_token) { create(:deploy_token, read_registry: false, projects: [project]) }
+ let(:login) { deploy_token.username }
+
+ it 'succeeds when login and token are valid' do
+ auth_success = Gitlab::Auth::Result.new(deploy_token, project, :deploy_token, [:download_code])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: login)
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_success)
+ end
+
+ it 'fails when login is not valid' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'random_login')
+ expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails when token is not valid' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, '123123', project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails if token is nil' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, nil, project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails if token is not related to project' do
+ another_deploy_token = create(:deploy_token)
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, another_deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails if token has been revoked' do
+ deploy_token.revoke!
+
+ expect(deploy_token.revoked?).to be_truthy
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'deploy-token')
+ expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+ end
+
+ context 'when the deploy token has read_registry as a scope' do
+ let(:deploy_token) { create(:deploy_token, read_repository: false, projects: [project]) }
+ let(:login) { deploy_token.username }
+
+ context 'when registry enabled' do
+ before do
+ stub_container_registry_config(enabled: true)
+ end
+
+ it 'succeeds when login and token are valid' do
+ auth_success = Gitlab::Auth::Result.new(deploy_token, project, :deploy_token, [:read_container_image])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: login)
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: nil, ip: 'ip'))
+ .to eq(auth_success)
+ end
+
+ it 'fails when login is not valid' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'random_login')
+ expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails when token is not valid' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, '123123', project: project, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails if token is nil' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, nil, project: nil, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails if token is not related to project' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, 'abcdef', project: nil, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+
+ it 'fails if token has been revoked' do
+ deploy_token.revoke!
+
+ expect(deploy_token.revoked?).to be_truthy
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'deploy-token')
+ expect(gl_auth.find_for_git_client('deploy-token', deploy_token.token, project: nil, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+ end
+
+ context 'when registry disabled' do
+ before do
+ stub_container_registry_config(enabled: false)
+ end
+
+ it 'fails when login and token are valid' do
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: login)
+ expect(gl_auth.find_for_git_client(login, deploy_token.token, project: nil, ip: 'ip'))
+ .to eq(auth_failure)
+ end
+ end
+ end
+ end
end
describe 'find_with_user_password' do
diff --git a/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb b/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb
new file mode 100644
index 00000000000..f8107dd40b9
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_stage_index_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::MigrateStageIndex, :migration, schema: 20180420080616 do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:stages) { table(:ci_stages) }
+ let(:jobs) { table(:ci_builds) }
+
+ before do
+ namespaces.create(id: 10, name: 'gitlab-org', path: 'gitlab-org')
+ projects.create!(id: 11, namespace_id: 10, name: 'gitlab', path: 'gitlab')
+ pipelines.create!(id: 12, project_id: 11, ref: 'master', sha: 'adf43c3a')
+
+ stages.create(id: 100, project_id: 11, pipeline_id: 12, name: 'build')
+ stages.create(id: 101, project_id: 11, pipeline_id: 12, name: 'test')
+
+ jobs.create!(id: 121, commit_id: 12, project_id: 11,
+ stage_idx: 2, stage_id: 100)
+ jobs.create!(id: 122, commit_id: 12, project_id: 11,
+ stage_idx: 2, stage_id: 100)
+ jobs.create!(id: 123, commit_id: 12, project_id: 11,
+ stage_idx: 10, stage_id: 100)
+ jobs.create!(id: 124, commit_id: 12, project_id: 11,
+ stage_idx: 3, stage_id: 101)
+ end
+
+ it 'correctly migrates stages indices' do
+ expect(stages.all.pluck(:position)).to all(be_nil)
+
+ described_class.new.perform(100, 101)
+
+ expect(stages.all.pluck(:position)).to eq [2, 3]
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb
new file mode 100644
index 00000000000..6f3fb994f17
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_services_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnServices, :migration, schema: 20180122154930 do
+ let(:services) { table(:services) }
+
+ describe '#perform' do
+ it 'migrates services where note_events is true' do
+ service = services.create(confidential_note_events: nil, note_events: true)
+
+ subject.perform(service.id, service.id)
+
+ expect(service.reload.confidential_note_events).to eq(true)
+ end
+
+ it 'ignores services where note_events is false' do
+ service = services.create(confidential_note_events: nil, note_events: false)
+
+ subject.perform(service.id, service.id)
+
+ expect(service.reload.confidential_note_events).to eq(nil)
+ end
+
+ it 'ignores services where confidential_note_events has already been set' do
+ service = services.create(confidential_note_events: false, note_events: true)
+
+ subject.perform(service.id, service.id)
+
+ expect(service.reload.confidential_note_events).to eq(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb
new file mode 100644
index 00000000000..82b484b7d5b
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/set_confidential_note_events_on_webhooks_spec.rb
@@ -0,0 +1,31 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::SetConfidentialNoteEventsOnWebhooks, :migration, schema: 20180104131052 do
+ let(:web_hooks) { table(:web_hooks) }
+
+ describe '#perform' do
+ it 'migrates hooks where note_events is true' do
+ hook = web_hooks.create(confidential_note_events: nil, note_events: true)
+
+ subject.perform(hook.id, hook.id)
+
+ expect(hook.reload.confidential_note_events).to eq(true)
+ end
+
+ it 'ignores hooks where note_events is false' do
+ hook = web_hooks.create(confidential_note_events: nil, note_events: false)
+
+ subject.perform(hook.id, hook.id)
+
+ expect(hook.reload.confidential_note_events).to eq(nil)
+ end
+
+ it 'ignores hooks where confidential_note_events has already been set' do
+ hook = web_hooks.create(confidential_note_events: false, note_events: true)
+
+ subject.perform(hook.id, hook.id)
+
+ expect(hook.reload.confidential_note_events).to eq(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index eb4b9d8b12f..5c8a19a53bc 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -4,6 +4,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
let!(:admin) { create(:admin) }
let!(:base_dir) { Dir.mktmpdir + '/' }
let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) }
+ let(:gitlab_shell) { Gitlab::Shell.new }
subject(:importer) { described_class.new(admin, bare_repository) }
@@ -84,12 +85,14 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
importer.create_project_if_needed
project = Project.find_by_full_path(project_path)
- repo_path = File.join(project.repository_storage_path, project.disk_path + '.git')
+ repo_path = "#{project.disk_path}.git"
hook_path = File.join(repo_path, 'hooks')
- expect(File).to exist(repo_path)
- expect(File.symlink?(hook_path)).to be true
- expect(File.readlink(hook_path)).to eq(Gitlab.config.gitlab_shell.hooks_path)
+ expect(gitlab_shell.exists?(project.repository_storage, repo_path)).to be(true)
+ expect(gitlab_shell.exists?(project.repository_storage, hook_path)).to be(true)
+
+ full_hook_path = File.join(project.repository.path_to_repo, 'hooks')
+ expect(File.readlink(full_hook_path)).to eq(Gitlab.config.gitlab_shell.hooks_path)
end
context 'hashed storage enabled' do
@@ -144,8 +147,8 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
project = Project.find_by_full_path("#{admin.full_path}/#{project_path}")
- expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.git'))
- expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.wiki.git'))
+ expect(gitlab_shell.exists?(project.repository_storage, project.disk_path + '.git')).to be(true)
+ expect(gitlab_shell.exists?(project.repository_storage, project.disk_path + '.wiki.git')).to be(true)
end
it 'moves an existing project to the correct path' do
@@ -155,7 +158,9 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
project = build(:project, :legacy_storage, :repository)
original_commit_count = project.repository.commit_count
- bare_repo = Gitlab::BareRepositoryImport::Repository.new(project.repository_storage_path, project.repository.path)
+ legacy_path = Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
+
+ bare_repo = Gitlab::BareRepositoryImport::Repository.new(legacy_path, project.repository.path)
gitlab_importer = described_class.new(admin, bare_repo)
expect(gitlab_importer).to receive(:create_project).and_call_original
@@ -183,7 +188,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
project = Project.find_by_full_path(project_path)
- expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.wiki.git'))
+ expect(gitlab_shell.exists?(project.repository_storage, project.disk_path + '.wiki.git')).to be(true)
end
end
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index 0dc3705825d..1504826c7a5 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -67,7 +67,7 @@ describe ::Gitlab::BareRepositoryImport::Repository do
end
after do
- gitlab_shell.remove_repository(root_path, hashed_path)
+ gitlab_shell.remove_repository(repository_storage, hashed_path)
end
subject { described_class.new(root_path, repo_path) }
diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
index ae5b31dc12d..c3f528dd6fc 100644
--- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::BitbucketImport::ProjectCreator do
has_wiki?: false)
end
- let(:namespace) { create(:group, owner: user) }
+ let(:namespace) { create(:group) }
let(:token) { "asdasd12345" }
let(:secret) { "sekrettt" }
let(:access_params) { { bitbucket_access_token: token, bitbucket_access_token_secret: secret } }
diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
index 16704ff5e77..18658588a40 100644
--- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
+++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do
let!(:project) { create(:project, :repository) }
let(:pipeline_status) { described_class.new(project) }
- let(:cache_key) { "projects/#{project.id}/pipeline_status" }
+ let(:cache_key) { described_class.cache_key_for_project(project) }
describe '.load_for_project' do
it "loads the status" do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
index dc12ba076bc..0edc3f315bb 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb
@@ -17,7 +17,7 @@ describe Gitlab::Ci::Pipeline::Chain::Create do
context 'when pipeline is ready to be saved' do
before do
- pipeline.stages.build(name: 'test', project: project)
+ pipeline.stages.build(name: 'test', position: 0, project: project)
step.perform!
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 8312fa47cfa..4d7d6951a51 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -35,11 +35,6 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
it 'populates pipeline with stages' do
expect(pipeline.stages).to be_one
expect(pipeline.stages.first).not_to be_persisted
- end
-
- it 'populates pipeline with builds' do
- expect(pipeline.builds).to be_one
- expect(pipeline.builds.first).not_to be_persisted
expect(pipeline.stages.first.builds).to be_one
expect(pipeline.stages.first.builds.first).not_to be_persisted
end
@@ -151,8 +146,8 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
step.perform!
expect(pipeline.stages.size).to eq 1
- expect(pipeline.builds.size).to eq 1
- expect(pipeline.builds.first.name).to eq 'rspec'
+ expect(pipeline.stages.first.builds.size).to eq 1
+ expect(pipeline.stages.first.builds.first.name).to eq 'rspec'
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
index eb1b285c7bd..05ce3412fd8 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
@@ -24,7 +24,8 @@ describe Gitlab::Ci::Pipeline::Seed::Stage do
describe '#attributes' do
it 'returns hash attributes of a stage' do
expect(subject.attributes).to be_a Hash
- expect(subject.attributes).to include(:name, :project)
+ expect(subject.attributes)
+ .to include(:name, :position, :pipeline, :project)
end
end
diff --git a/spec/lib/gitlab/ci/status/build/action_spec.rb b/spec/lib/gitlab/ci/status/build/action_spec.rb
index d612d29e3e0..bdec582b57b 100644
--- a/spec/lib/gitlab/ci/status/build/action_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/action_spec.rb
@@ -53,4 +53,14 @@ describe Gitlab::Ci::Status::Build::Action do
end
end
end
+
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build, :non_playable) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ it 'returns the status' do
+ expect(subject.badge_tooltip).to eq('created')
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
index 9cdebaa5cf2..78d6fa65b5a 100644
--- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -40,6 +40,24 @@ describe Gitlab::Ci::Status::Build::Cancelable do
end
end
+ describe '#status_tooltip' do
+ it 'does not override status status_tooltip' do
+ expect(status).to receive(:status_tooltip)
+
+ subject.status_tooltip
+ end
+ end
+
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ it 'returns the status' do
+ expect(subject.badge_tooltip).to eq('pending')
+ end
+ end
+
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
@@ -72,6 +90,10 @@ describe Gitlab::Ci::Status::Build::Cancelable do
describe '#action_title' do
it { expect(subject.action_title).to eq 'Cancel' }
end
+
+ describe '#action_button_title' do
+ it { expect(subject.action_button_title).to eq 'Cancel this job' }
+ end
end
describe '.matches?' do
diff --git a/spec/lib/gitlab/ci/status/build/canceled_spec.rb b/spec/lib/gitlab/ci/status/build/canceled_spec.rb
new file mode 100644
index 00000000000..c6b5cc68770
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/canceled_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Canceled do
+ let(:user) { create(:user) }
+
+ subject do
+ described_class.new(double('subject'))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title) }
+ end
+
+ describe '.matches?' do
+ subject {described_class.matches?(build, user) }
+
+ context 'when build is canceled' do
+ let(:build) { create(:ci_build, :canceled) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not canceled' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
index 2cce7a23ea7..ca3c66f0152 100644
--- a/spec/lib/gitlab/ci/status/build/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -38,4 +38,10 @@ describe Gitlab::Ci::Status::Build::Common do
expect(subject.details_path).to include "jobs/#{build.id}"
end
end
+
+ describe '#illustration' do
+ it 'provides a fallback empty state illustration' do
+ expect(subject.illustration).not_to be_empty
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/status/build/created_spec.rb b/spec/lib/gitlab/ci/status/build/created_spec.rb
new file mode 100644
index 00000000000..8bdfe6ef7a2
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/created_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Created do
+ let(:user) { create(:user) }
+
+ subject do
+ described_class.new(double('subject'))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title, :content) }
+ end
+
+ describe '.matches?' do
+ subject {described_class.matches?(build, user) }
+
+ context 'when build is created' do
+ let(:build) { create(:ci_build, :created) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not created' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/erased_spec.rb b/spec/lib/gitlab/ci/status/build/erased_spec.rb
new file mode 100644
index 00000000000..0acd271e375
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/erased_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Erased do
+ let(:user) { create(:user) }
+
+ subject do
+ described_class.new(double('subject'))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title) }
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is erased' do
+ let(:build) { create(:ci_build, :success, :erased) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not erased' do
+ let(:build) { create(:ci_build, :success, :trace_artifact) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
index d196bc6a4c2..d53a7d468e3 100644
--- a/spec/lib/gitlab/ci/status/build/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::Ci::Status::Build::Factory do
end
context 'when build is successful' do
- let(:build) { create(:ci_build, :success) }
+ let(:build) { create(:ci_build, :success, :trace_artifact) }
it 'matches correct core status' do
expect(factory.core_status).to be_a Gitlab::Ci::Status::Success
@@ -38,6 +38,33 @@ describe Gitlab::Ci::Status::Build::Factory do
end
end
+ context 'when build is erased' do
+ let(:build) { create(:ci_build, :success, :erased) }
+
+ 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::Erased,
+ 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 'passed'
+ expect(status.icon).to eq '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
+ end
+ end
+
context 'when build is failed' do
context 'when build is not allowed to fail' do
let(:build) { create(:ci_build, :failed) }
@@ -48,11 +75,12 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
- .to eq [Gitlab::Ci::Status::Build::Retryable]
+ .to eq [Gitlab::Ci::Status::Build::Retryable,
+ Gitlab::Ci::Status::Build::Failed]
end
- it 'fabricates a retryable build status' do
- expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ it 'fabricates a failed build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Failed
end
it 'fabricates status with correct details' do
@@ -60,13 +88,14 @@ describe Gitlab::Ci::Status::Build::Factory do
expect(status.icon).to eq 'status_failed'
expect(status.favicon).to eq 'favicon_status_failed'
expect(status.label).to eq 'failed'
+ expect(status.status_tooltip).to eq 'failed <br> (unknown failure)'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is allowed to fail' do
- let(:build) { create(:ci_build, :failed, :allowed_to_fail) }
+ let(:build) { create(:ci_build, :failed, :allowed_to_fail, :trace_artifact) }
it 'matches correct core status' do
expect(factory.core_status).to be_a Gitlab::Ci::Status::Failed
@@ -75,6 +104,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
.to eq [Gitlab::Ci::Status::Build::Retryable,
+ Gitlab::Ci::Status::Build::Failed,
Gitlab::Ci::Status::Build::FailedAllowed]
end
@@ -104,7 +134,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
- .to eq [Gitlab::Ci::Status::Build::Retryable]
+ .to eq [Gitlab::Ci::Status::Build::Canceled, Gitlab::Ci::Status::Build::Retryable]
end
it 'fabricates a retryable build status' do
@@ -115,6 +145,7 @@ describe Gitlab::Ci::Status::Build::Factory do
expect(status.text).to eq 'canceled'
expect(status.icon).to eq 'status_canceled'
expect(status.favicon).to eq 'favicon_status_canceled'
+ expect(status.illustration).to include(:image, :size, :title)
expect(status.label).to eq 'canceled'
expect(status).to have_details
expect(status).to have_action
@@ -156,7 +187,7 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
- .to eq [Gitlab::Ci::Status::Build::Cancelable]
+ .to eq [Gitlab::Ci::Status::Build::Pending, Gitlab::Ci::Status::Build::Cancelable]
end
it 'fabricates a cancelable build status' do
@@ -167,6 +198,7 @@ describe Gitlab::Ci::Status::Build::Factory do
expect(status.text).to eq 'pending'
expect(status.icon).to eq 'status_pending'
expect(status.favicon).to eq 'favicon_status_pending'
+ expect(status.illustration).to include(:image, :size, :title, :content)
expect(status.label).to eq 'pending'
expect(status).to have_details
expect(status).to have_action
@@ -180,18 +212,19 @@ describe Gitlab::Ci::Status::Build::Factory 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
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses).to eq [Gitlab::Ci::Status::Build::Skipped]
end
- it 'fabricates a core skipped status' do
- expect(status).to be_a Gitlab::Ci::Status::Skipped
+ it 'fabricates a skipped build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Skipped
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'skipped'
expect(status.icon).to eq 'status_skipped'
expect(status.favicon).to eq 'favicon_status_skipped'
+ expect(status.illustration).to include(:image, :size, :title)
expect(status.label).to eq 'skipped'
expect(status).to have_details
expect(status).not_to have_action
@@ -208,7 +241,8 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
- .to eq [Gitlab::Ci::Status::Build::Play,
+ .to eq [Gitlab::Ci::Status::Build::Manual,
+ Gitlab::Ci::Status::Build::Play,
Gitlab::Ci::Status::Build::Action]
end
@@ -221,6 +255,7 @@ describe Gitlab::Ci::Status::Build::Factory do
expect(status.group).to eq 'manual'
expect(status.icon).to eq 'status_manual'
expect(status.favicon).to eq 'favicon_status_manual'
+ expect(status.illustration).to include(:image, :size, :title, :content)
expect(status.label).to include 'manual play action'
expect(status).to have_details
expect(status.action_path).to include 'play'
@@ -255,7 +290,8 @@ describe Gitlab::Ci::Status::Build::Factory do
it 'matches correct extended statuses' do
expect(factory.extended_statuses)
- .to eq [Gitlab::Ci::Status::Build::Stop,
+ .to eq [Gitlab::Ci::Status::Build::Manual,
+ Gitlab::Ci::Status::Build::Stop,
Gitlab::Ci::Status::Build::Action]
end
diff --git a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
index 99a5a7e4aca..bfaa508785e 100644
--- a/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/failed_allowed_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Build::FailedAllowed do
let(:status) { double('core status') }
let(:user) { double('user') }
+ let(:build) { create(:ci_build, :failed, :allowed_to_fail) }
subject do
described_class.new(status)
@@ -68,6 +69,28 @@ describe Gitlab::Ci::Status::Build::FailedAllowed do
end
end
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:failed_status) { Gitlab::Ci::Status::Failed.new(build, user) }
+ let(:build_status) { Gitlab::Ci::Status::Build::Failed.new(failed_status) }
+ let(:status) { described_class.new(build_status) }
+
+ it 'does override badge_tooltip' do
+ expect(status.badge_tooltip).to eq('failed <br> (unknown failure)')
+ end
+ end
+
+ describe '#status_tooltip' do
+ let(:user) { create(:user) }
+ let(:failed_status) { Gitlab::Ci::Status::Failed.new(build, user) }
+ let(:build_status) { Gitlab::Ci::Status::Build::Failed.new(failed_status) }
+ let(:status) { described_class.new(build_status) }
+
+ it 'does override status_tooltip' do
+ expect(status.status_tooltip).to eq 'failed <br> (unknown failure) (allowed to fail)'
+ end
+ end
+
describe '.matches?' do
subject { described_class.matches?(build, user) }
diff --git a/spec/lib/gitlab/ci/status/build/failed_spec.rb b/spec/lib/gitlab/ci/status/build/failed_spec.rb
new file mode 100644
index 00000000000..cadb424ea2c
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/failed_spec.rb
@@ -0,0 +1,83 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Failed do
+ let(:build) { create(:ci_build, :script_failure) }
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject { described_class.new(status) }
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'does not override status icon' do
+ expect(status).to receive(:icon)
+
+ subject.icon
+ end
+ end
+
+ describe '#group' do
+ it 'does not override status group' do
+ expect(status).to receive(:group)
+
+ subject.group
+ end
+ end
+
+ describe '#favicon' do
+ it 'does not override status label' do
+ expect(status).to receive(:favicon)
+
+ subject.favicon
+ end
+ end
+
+ describe '#label' do
+ it 'does not override label' do
+ expect(status).to receive(:label)
+
+ subject.label
+ end
+ end
+
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:status) { Gitlab::Ci::Status::Failed.new(build, user) }
+
+ it 'does override badge_tooltip' do
+ expect(subject.badge_tooltip).to eq 'failed <br> (script failure)'
+ end
+ end
+
+ describe '#status_tooltip' do
+ let(:user) { create(:user) }
+ let(:status) { Gitlab::Ci::Status::Failed.new(build, user) }
+
+ it 'does override status_tooltip' do
+ expect(subject.status_tooltip).to eq 'failed <br> (script failure)'
+ end
+ end
+
+ describe '.matches?' do
+ context 'with a failed build' do
+ it 'returns true' do
+ expect(described_class.matches?(build, user)).to be_truthy
+ end
+ end
+
+ context 'with any other type of build' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'returns false' do
+ expect(described_class.matches?(build, user)).to be_falsy
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/manual_spec.rb b/spec/lib/gitlab/ci/status/build/manual_spec.rb
new file mode 100644
index 00000000000..6386296f992
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/manual_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Manual do
+ let(:user) { create(:user) }
+
+ subject do
+ build = create(:ci_build, :manual)
+ described_class.new(Gitlab::Ci::Status::Core.new(build, user))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title, :content) }
+ end
+
+ describe '.matches?' do
+ subject {described_class.matches?(build, user) }
+
+ context 'when build is manual' do
+ let(:build) { create(:ci_build, :manual) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not manual' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/pending_spec.rb b/spec/lib/gitlab/ci/status/build/pending_spec.rb
new file mode 100644
index 00000000000..4cf70828e53
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/pending_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Pending do
+ let(:user) { create(:user) }
+
+ subject do
+ described_class.new(double('subject'))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title, :content) }
+ end
+
+ describe '.matches?' do
+ subject {described_class.matches?(build, user) }
+
+ context 'when build is pending' do
+ let(:build) { create(:ci_build, :pending) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not pending' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ 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 81d5f553fd1..e2bb378f663 100644
--- a/spec/lib/gitlab/ci/status/build/play_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Build::Play do
let(:user) { create(:user) }
- let(:project) { build.project }
- let(:build) { create(:ci_build, :manual) }
+ let(:project) { create(:project, :stubbed_repository) }
+ let(:build) { create(:ci_build, :manual, project: project) }
let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
subject { described_class.new(status) }
@@ -14,6 +14,22 @@ describe Gitlab::Ci::Status::Build::Play do
end
end
+ describe '#status_tooltip' do
+ it 'does not override status status_tooltip' do
+ expect(status).to receive(:status_tooltip)
+
+ subject.status_tooltip
+ end
+ end
+
+ describe '#badge_tooltip' do
+ it 'does not override status badge_tooltip' do
+ expect(status).to receive(:badge_tooltip)
+
+ subject.badge_tooltip
+ end
+ end
+
describe '#has_action?' do
context 'when user is allowed to update build' do
context 'when user is allowed to trigger protected action' do
@@ -30,6 +46,8 @@ describe Gitlab::Ci::Status::Build::Play do
context 'when user can not push to the branch' do
before do
build.project.add_developer(user)
+ create(:protected_branch, :masters_can_push,
+ name: build.ref, project: project)
end
it { is_expected.not_to have_action }
@@ -53,6 +71,10 @@ describe Gitlab::Ci::Status::Build::Play do
it { expect(subject.action_title).to eq 'Play' }
end
+ describe '#action_button_title' do
+ it { expect(subject.action_button_title).to eq 'Trigger this manual action' }
+ end
+
describe '.matches?' do
subject { described_class.matches?(build, user) }
diff --git a/spec/lib/gitlab/ci/status/build/retried_spec.rb b/spec/lib/gitlab/ci/status/build/retried_spec.rb
new file mode 100644
index 00000000000..ee9acaf1c21
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/retried_spec.rb
@@ -0,0 +1,96 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Retried do
+ let(:build) { create(:ci_build, :retried) }
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject { described_class.new(status) }
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'does not override status icon' do
+ expect(status).to receive(:icon)
+
+ subject.icon
+ end
+ end
+
+ describe '#group' do
+ it 'does not override status group' do
+ expect(status).to receive(:group)
+
+ subject.group
+ end
+ end
+
+ describe '#favicon' do
+ it 'does not override status label' do
+ expect(status).to receive(:favicon)
+
+ subject.favicon
+ end
+ end
+
+ describe '#label' do
+ it 'does not override status label' do
+ expect(status).to receive(:label)
+
+ subject.label
+ end
+ end
+
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build, :retried) }
+ let(:status) { Gitlab::Ci::Status::Success.new(build, user) }
+
+ it 'returns status' do
+ expect(status.badge_tooltip).to eq('pending')
+ end
+ end
+
+ describe '#status_tooltip' do
+ let(:user) { create(:user) }
+
+ context 'with a failed build' do
+ let(:build) { create(:ci_build, :failed, :retried) }
+ let(:failed_status) { Gitlab::Ci::Status::Failed.new(build, user) }
+ let(:status) { Gitlab::Ci::Status::Build::Failed.new(failed_status) }
+
+ it 'does override status_tooltip' do
+ expect(subject.status_tooltip).to eq 'failed <br> (unknown failure) (retried)'
+ end
+ end
+
+ context 'with another build' do
+ let(:build) { create(:ci_build, :retried) }
+ let(:status) { Gitlab::Ci::Status::Success.new(build, user) }
+
+ it 'does override status_tooltip' do
+ expect(subject.status_tooltip).to eq 'passed (retried)'
+ end
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'with a retried build' do
+ it { is_expected.to be_truthy }
+ end
+
+ context 'with a build that has not been retried' do
+ let(:build) { create(:ci_build, :success) }
+
+ it { is_expected.to be_falsy }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
index 14d42e0d70f..84d98588f2d 100644
--- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -40,6 +40,24 @@ describe Gitlab::Ci::Status::Build::Retryable do
end
end
+ describe '#status_tooltip' do
+ it 'does not override status status_tooltip' do
+ expect(status).to receive(:status_tooltip)
+
+ subject.status_tooltip
+ end
+ end
+
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ it 'does return status' do
+ expect(status.badge_tooltip).to eq('pending')
+ end
+ end
+
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
@@ -72,6 +90,10 @@ describe Gitlab::Ci::Status::Build::Retryable do
describe '#action_title' do
it { expect(subject.action_title).to eq 'Retry' }
end
+
+ describe '#action_button_title' do
+ it { expect(subject.action_button_title).to eq 'Retry this job' }
+ end
end
describe '.matches?' do
diff --git a/spec/lib/gitlab/ci/status/build/skipped_spec.rb b/spec/lib/gitlab/ci/status/build/skipped_spec.rb
new file mode 100644
index 00000000000..46f6933025a
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/skipped_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Skipped do
+ let(:user) { create(:user) }
+
+ subject do
+ described_class.new(double('subject'))
+ end
+
+ describe '#illustration' do
+ it { expect(subject.illustration).to include(:image, :size, :title) }
+ end
+
+ describe '.matches?' do
+ subject {described_class.matches?(build, user) }
+
+ context 'when build is skipped' do
+ let(:build) { create(:ci_build, :skipped) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not skipped' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
index 18e250772f0..5b7534c96c1 100644
--- a/spec/lib/gitlab/ci/status/build/stop_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -44,6 +44,10 @@ describe Gitlab::Ci::Status::Build::Stop do
describe '#action_title' do
it { expect(subject.action_title).to eq 'Stop' }
end
+
+ describe '#action_button_title' do
+ it { expect(subject.action_button_title).to eq 'Stop this environment' }
+ end
end
describe '.matches?' do
@@ -77,4 +81,24 @@ describe Gitlab::Ci::Status::Build::Stop do
end
end
end
+
+ describe '#status_tooltip' do
+ it 'does not override status status_tooltip' do
+ expect(status).to receive(:status_tooltip)
+
+ subject.status_tooltip
+ end
+ end
+
+ describe '#badge_tooltip' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build, :playable) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ it 'does not override status badge_tooltip' do
+ expect(status).to receive(:badge_tooltip)
+
+ subject.badge_tooltip
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/status/success_warning_spec.rb b/spec/lib/gitlab/ci/status/success_warning_spec.rb
index 4582354e739..6d05545d1d8 100644
--- a/spec/lib/gitlab/ci/status/success_warning_spec.rb
+++ b/spec/lib/gitlab/ci/status/success_warning_spec.rb
@@ -1,8 +1,10 @@
require 'spec_helper'
describe Gitlab::Ci::Status::SuccessWarning do
+ let(:status) { double('status') }
+
subject do
- described_class.new(double('status'))
+ described_class.new(status)
end
describe '#test' do
diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb
index 3a9371ed2e8..6a9c6442282 100644
--- a/spec/lib/gitlab/ci/trace_spec.rb
+++ b/spec/lib/gitlab/ci/trace_spec.rb
@@ -458,7 +458,7 @@ describe Gitlab::Ci::Trace do
context 'when job does not have trace artifact' do
context 'when trace file stored in default path' do
let!(:build) { create(:ci_build, :success, :trace_live) }
- let!(:src_path) { trace.read { |s| return s.path } }
+ let!(:src_path) { trace.read { |s| s.path } }
let!(:src_checksum) { Digest::SHA256.file(src_path).hexdigest }
it_behaves_like 'archive trace file'
diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
index bf9208f1ff4..e79f0a7f257 100644
--- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
@@ -5,6 +5,18 @@ describe Gitlab::Ci::Variables::Collection::Item do
{ key: 'VAR', value: 'something', public: true }
end
+ describe '.new' do
+ it 'raises error if unknown key i specified' do
+ expect { described_class.new(key: 'VAR', value: 'abc', files: true) }
+ .to raise_error ArgumentError, 'unknown keyword: files'
+ end
+
+ it 'raises error when required keywords are not specified' do
+ expect { described_class.new(key: 'VAR') }
+ .to raise_error ArgumentError, 'missing keyword: value'
+ end
+ end
+
describe '.fabricate' do
it 'supports using a hash' do
resource = described_class.fabricate(variable)
@@ -47,12 +59,25 @@ describe Gitlab::Ci::Variables::Collection::Item do
end
describe '#to_runner_variable' do
- it 'returns a runner-compatible hash representation' do
- runner_variable = described_class
- .new(**variable)
- .to_runner_variable
+ context 'when variable is not a file-related' do
+ it 'returns a runner-compatible hash representation' do
+ runner_variable = described_class
+ .new(**variable)
+ .to_runner_variable
+
+ expect(runner_variable).to eq variable
+ end
+ end
+
+ context 'when variable is file-related' do
+ it 'appends file description component' do
+ runner_variable = described_class
+ .new(key: 'VAR', value: 'value', file: true)
+ .to_runner_variable
- expect(runner_variable).to eq variable
+ expect(runner_variable)
+ .to eq(key: 'VAR', value: 'value', public: true, file: true)
+ 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 aaa42566a4d..4f8412108ba 100644
--- a/spec/lib/gitlab/data_builder/note_spec.rb
+++ b/spec/lib/gitlab/data_builder/note_spec.rb
@@ -55,6 +55,14 @@ describe Gitlab::DataBuilder::Note do
.to be > issue.hook_attrs['updated_at']
end
+ context 'with confidential issue' do
+ let(:issue) { create(:issue, project: project, confidential: true) }
+
+ it 'sets event_type to confidential_note' do
+ expect(data[:event_type]).to eq('confidential_note')
+ end
+ end
+
include_examples 'project hook data'
include_examples 'deprecated repository hook data'
end
diff --git a/spec/lib/gitlab/database/sha_attribute_spec.rb b/spec/lib/gitlab/database/sha_attribute_spec.rb
index 62c1d37ea1c..778bfa2cc47 100644
--- a/spec/lib/gitlab/database/sha_attribute_spec.rb
+++ b/spec/lib/gitlab/database/sha_attribute_spec.rb
@@ -19,15 +19,15 @@ describe Gitlab::Database::ShaAttribute do
let(:attribute) { described_class.new }
- describe '#type_cast_from_database' do
+ describe '#deserialize' do
it 'converts the binary SHA to a String' do
- expect(attribute.type_cast_from_database(binary_from_db)).to eq(sha)
+ expect(attribute.deserialize(binary_from_db)).to eq(sha)
end
end
- describe '#type_cast_for_database' do
+ describe '#serialize' do
it 'converts a SHA String to binary data' do
- expect(attribute.type_cast_for_database(sha).to_s).to eq(binary_sha)
+ expect(attribute.serialize(sha).to_s).to eq(binary_sha)
end
end
end
diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb
index 73d60c021c8..7c9e8c8d04e 100644
--- a/spec/lib/gitlab/diff/highlight_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_spec.rb
@@ -79,6 +79,8 @@ describe Gitlab::Diff::Highlight do
end
it 'keeps the original rich line' do
+ allow(Gitlab::Sentry).to receive(:track_exception)
+
code = %q{+ raise RuntimeError, "System commands must be given as an array of strings"}
expect(subject[5].text).to eq(code)
@@ -86,12 +88,9 @@ describe Gitlab::Diff::Highlight do
end
it 'reports to Sentry if configured' do
- allow(Gitlab::Sentry).to receive(:enabled?).and_return(true)
-
- expect(Gitlab::Sentry).to receive(:context)
- expect(Raven).to receive(:capture_exception)
+ expect(Gitlab::Sentry).to receive(:track_exception).and_call_original
- subject
+ expect { subject }. to raise_exception(RangeError)
end
end
end
diff --git a/spec/lib/gitlab/email/handler_spec.rb b/spec/lib/gitlab/email/handler_spec.rb
index 650b01c4df4..cedbfcc0d18 100644
--- a/spec/lib/gitlab/email/handler_spec.rb
+++ b/spec/lib/gitlab/email/handler_spec.rb
@@ -14,4 +14,34 @@ describe Gitlab::Email::Handler do
expect(described_class.for('email', '')).to be_nil
end
end
+
+ describe 'regexps are set properly' do
+ let(:addresses) do
+ %W(sent_notification_key#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX} sent_notification_key path/to/project+merge-request+user_email_token path/to/project+user_email_token)
+ end
+
+ it 'picks each handler at least once' do
+ matched_handlers = addresses.map do |address|
+ described_class.for('email', address).class
+ end
+
+ expect(matched_handlers.uniq).to match_array(ce_handlers)
+ end
+
+ it 'can pick exactly one handler for each address' do
+ addresses.each do |address|
+ matched_handlers = ce_handlers.select do |handler|
+ handler.new('email', address).can_handle?
+ end
+
+ expect(matched_handlers.count).to eq(1), "#{address} matches #{matched_handlers.count} handlers: #{matched_handlers}"
+ end
+ end
+ end
+
+ def ce_handlers
+ @ce_handlers ||= Gitlab::Email::Handler::HANDLERS.reject do |handler|
+ handler.name.start_with?('Gitlab::Email::Handler::EE::')
+ end
+ end
end
diff --git a/spec/lib/gitlab/git/attributes_parser_spec.rb b/spec/lib/gitlab/git/attributes_parser_spec.rb
index 323334e99a5..2d103123998 100644
--- a/spec/lib/gitlab/git/attributes_parser_spec.rb
+++ b/spec/lib/gitlab/git/attributes_parser_spec.rb
@@ -66,18 +66,6 @@ describe Gitlab::Git::AttributesParser, seed_helper: true do
end
end
- context 'when attributes data is a file handle' do
- subject do
- File.open(attributes_path, 'r') do |file_handle|
- described_class.new(file_handle)
- end
- end
-
- it 'returns the attributes as a Hash' do
- expect(subject.attributes('test.txt')).to eq({ 'text' => true })
- end
- end
-
context 'when attributes data is nil' do
let(:data) { nil }
diff --git a/spec/lib/gitlab/git/checksum_spec.rb b/spec/lib/gitlab/git/checksum_spec.rb
deleted file mode 100644
index 8ff310905bf..00000000000
--- a/spec/lib/gitlab/git/checksum_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Git::Checksum, seed_helper: true do
- let(:storage) { 'default' }
-
- it 'raises Gitlab::Git::Repository::NoRepository when there is no repo' do
- checksum = described_class.new(storage, 'nonexistent-repo')
-
- expect { checksum.calculate }.to raise_error Gitlab::Git::Repository::NoRepository
- end
-
- it 'pretends that checksum is 000000... when the repo is empty' do
- FileUtils.rm_rf(File.join(SEED_STORAGE_PATH, 'empty-repo.git'))
-
- system(git_env, *%W(#{Gitlab.config.git.bin_path} init --bare empty-repo.git),
- chdir: SEED_STORAGE_PATH,
- out: '/dev/null',
- err: '/dev/null')
-
- checksum = described_class.new(storage, 'empty-repo')
-
- expect(checksum.calculate).to eq '0000000000000000000000000000000000000000'
- end
-
- it 'raises Gitlab::Git::Repository::Failure when shelling out to git return non-zero status' do
- checksum = described_class.new(storage, 'gitlab-git-test')
-
- allow(checksum).to receive(:popen).and_return(['output', nil])
-
- expect { checksum.calculate }.to raise_error Gitlab::Git::Checksum::Failure
- end
-
- it 'calculates the checksum when there is a repo' do
- checksum = described_class.new(storage, 'gitlab-git-test')
-
- expect(checksum.calculate).to eq '54f21be4c32c02f6788d72207fa03ad3bce725e4'
- end
-end
diff --git a/spec/lib/gitlab/git/committer_with_hooks_spec.rb b/spec/lib/gitlab/git/committer_with_hooks_spec.rb
new file mode 100644
index 00000000000..267056b96e6
--- /dev/null
+++ b/spec/lib/gitlab/git/committer_with_hooks_spec.rb
@@ -0,0 +1,154 @@
+require 'spec_helper'
+
+describe Gitlab::Git::CommitterWithHooks, seed_helper: true do
+ shared_examples 'calling wiki hooks' do
+ let(:project) { create(:project) }
+ let(:user) { project.owner }
+ let(:project_wiki) { ProjectWiki.new(project, user) }
+ let(:wiki) { project_wiki.wiki }
+ let(:options) do
+ {
+ id: user.id,
+ username: user.username,
+ name: user.name,
+ email: user.email,
+ message: 'commit message'
+ }
+ end
+
+ subject { described_class.new(wiki, options) }
+
+ before do
+ project_wiki.create_page('home', 'test content')
+ end
+
+ shared_examples 'failing pre-receive hook' do
+ before do
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([false, ''])
+ expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('update')
+ expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('post-receive')
+ end
+
+ it 'raises exception' do
+ expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+ end
+
+ it 'does not create a new commit inside the repository' do
+ current_rev = find_current_rev
+
+ expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+
+ expect(current_rev).to eq find_current_rev
+ end
+ end
+
+ shared_examples 'failing update hook' do
+ before do
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([true, ''])
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('update').and_return([false, ''])
+ expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('post-receive')
+ end
+
+ it 'raises exception' do
+ expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+ end
+
+ it 'does not create a new commit inside the repository' do
+ current_rev = find_current_rev
+
+ expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+
+ expect(current_rev).to eq find_current_rev
+ end
+ end
+
+ shared_examples 'failing post-receive hook' do
+ before do
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([true, ''])
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('update').and_return([true, ''])
+ expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('post-receive').and_return([false, ''])
+ end
+
+ it 'does not raise exception' do
+ expect { subject.commit }.not_to raise_error
+ end
+
+ it 'creates the commit' do
+ current_rev = find_current_rev
+
+ subject.commit
+
+ expect(current_rev).not_to eq find_current_rev
+ end
+ end
+
+ shared_examples 'when hooks call succceeds' do
+ let(:hook) { double(:hook) }
+
+ it 'calls the three hooks' do
+ expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
+ expect(hook).to receive(:trigger).exactly(3).times.and_return([true, nil])
+
+ subject.commit
+ end
+
+ it 'creates the commit' do
+ current_rev = find_current_rev
+
+ subject.commit
+
+ expect(current_rev).not_to eq find_current_rev
+ end
+ end
+
+ context 'when creating a page' do
+ before do
+ project_wiki.create_page('index', 'test content')
+ end
+
+ it_behaves_like 'failing pre-receive hook'
+ it_behaves_like 'failing update hook'
+ it_behaves_like 'failing post-receive hook'
+ it_behaves_like 'when hooks call succceeds'
+ end
+
+ context 'when updating a page' do
+ before do
+ project_wiki.update_page(find_page('home'), content: 'some other content', format: :markdown)
+ end
+
+ it_behaves_like 'failing pre-receive hook'
+ it_behaves_like 'failing update hook'
+ it_behaves_like 'failing post-receive hook'
+ it_behaves_like 'when hooks call succceeds'
+ end
+
+ context 'when deleting a page' do
+ before do
+ project_wiki.delete_page(find_page('home'))
+ end
+
+ it_behaves_like 'failing pre-receive hook'
+ it_behaves_like 'failing update hook'
+ it_behaves_like 'failing post-receive hook'
+ it_behaves_like 'when hooks call succceeds'
+ end
+
+ def find_current_rev
+ wiki.gollum_wiki.repo.commits.first&.sha
+ end
+
+ def find_page(name)
+ wiki.page(title: name)
+ end
+ end
+
+ # TODO: Uncomment once Gitaly updates the ruby vendor code
+ # context 'when Gitaly is enabled' do
+ # it_behaves_like 'calling wiki hooks'
+ # end
+
+ context 'when Gitaly is disabled', :skip_gitaly_mock do
+ it_behaves_like 'calling wiki hooks'
+ end
+end
diff --git a/spec/lib/gitlab/git/info_attributes_spec.rb b/spec/lib/gitlab/git/info_attributes_spec.rb
deleted file mode 100644
index ea84909c3e0..00000000000
--- a/spec/lib/gitlab/git/info_attributes_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Git::InfoAttributes, seed_helper: true do
- let(:path) do
- File.join(SEED_STORAGE_PATH, 'with-git-attributes.git')
- end
-
- subject { described_class.new(path) }
-
- describe '#attributes' do
- context 'using a path with attributes' do
- it 'returns the attributes as a Hash' do
- expect(subject.attributes('test.txt')).to eq({ 'text' => true })
- end
-
- it 'returns an empty Hash for a defined path without attributes' do
- expect(subject.attributes('bla/bla.txt')).to eq({})
- end
- end
- end
-
- describe '#parser' do
- it 'parses a file with entries' do
- expect(subject.patterns).to be_an_instance_of(Hash)
- expect(subject.patterns["/*.txt"]).to eq({ 'text' => true })
- end
-
- it 'does not parse anything when the attributes file does not exist' do
- expect(File).to receive(:exist?)
- .with(File.join(path, 'info/attributes'))
- .and_return(false)
-
- expect(subject.patterns).to eq({})
- end
-
- it 'does not parse attributes files with unsupported encoding' do
- path = File.join(SEED_STORAGE_PATH, 'with-invalid-git-attributes.git')
- subject = described_class.new(path)
-
- expect(subject.patterns).to eq({})
- end
- end
-end
diff --git a/spec/lib/gitlab/git/raw_diff_change_spec.rb b/spec/lib/gitlab/git/raw_diff_change_spec.rb
new file mode 100644
index 00000000000..eedde34534f
--- /dev/null
+++ b/spec/lib/gitlab/git/raw_diff_change_spec.rb
@@ -0,0 +1,66 @@
+require 'spec_helper'
+
+describe Gitlab::Git::RawDiffChange do
+ let(:raw_change) { }
+ let(:change) { described_class.new(raw_change) }
+
+ context 'bad input' do
+ let(:raw_change) { 'foo' }
+
+ it 'does not set most of the attrs' do
+ expect(change.blob_id).to eq('foo')
+ expect(change.operation).to eq(:unknown)
+ expect(change.old_path).to be_blank
+ expect(change.new_path).to be_blank
+ expect(change.blob_size).to be_blank
+ end
+ end
+
+ context 'adding a file' do
+ let(:raw_change) { '93e123ac8a3e6a0b600953d7598af629dec7b735 59 A bar/branch-test.txt' }
+
+ it 'initialize the proper attrs' do
+ expect(change.operation).to eq(:added)
+ expect(change.old_path).to be_blank
+ expect(change.new_path).to eq('bar/branch-test.txt')
+ expect(change.blob_id).to be_present
+ expect(change.blob_size).to be_present
+ end
+ end
+
+ context 'renaming a file' do
+ let(:raw_change) { "85bc2f9753afd5f4fc5d7c75f74f8d526f26b4f3 107 R060\tfiles/js/commit.js.coffee\tfiles/js/commit.coffee" }
+
+ it 'initialize the proper attrs' do
+ expect(change.operation).to eq(:renamed)
+ expect(change.old_path).to eq('files/js/commit.js.coffee')
+ expect(change.new_path).to eq('files/js/commit.coffee')
+ expect(change.blob_id).to be_present
+ expect(change.blob_size).to be_present
+ end
+ end
+
+ context 'modifying a file' do
+ let(:raw_change) { 'c60514b6d3d6bf4bec1030f70026e34dfbd69ad5 824 M README.md' }
+
+ it 'initialize the proper attrs' do
+ expect(change.operation).to eq(:modified)
+ expect(change.old_path).to eq('README.md')
+ expect(change.new_path).to eq('README.md')
+ expect(change.blob_id).to be_present
+ expect(change.blob_size).to be_present
+ end
+ end
+
+ context 'deleting a file' do
+ let(:raw_change) { '60d7a906c2fd9e4509aeb1187b98d0ea7ce827c9 15364 D files/.DS_Store' }
+
+ it 'initialize the proper attrs' do
+ expect(change.operation).to eq(:deleted)
+ expect(change.old_path).to eq('files/.DS_Store')
+ expect(change.new_path).to be_nil
+ expect(change.blob_id).to be_present
+ expect(change.blob_size).to be_present
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 5cbe2808d0b..9924641f829 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -234,53 +234,72 @@ describe Gitlab::Git::Repository, seed_helper: true do
it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :tag_names
end
- shared_examples 'archive check' do |extenstion|
- it { expect(metadata['ArchivePath']).to match(%r{tmp/gitlab-git-test.git/gitlab-git-test-master-#{SeedRepo::LastCommit::ID}}) }
- it { expect(metadata['ArchivePath']).to end_with extenstion }
- end
+ describe '#archive_metadata' do
+ let(:storage_path) { '/tmp' }
+ let(:cache_key) { File.join(repository.gl_repository, SeedRepo::LastCommit::ID) }
- describe '#archive_prefix' do
- let(:project_name) { 'project-name'}
+ let(:append_sha) { true }
+ let(:ref) { 'master' }
+ let(:format) { nil }
- before do
- expect(repository).to receive(:name).once.and_return(project_name)
- end
+ let(:expected_extension) { 'tar.gz' }
+ let(:expected_filename) { "#{expected_prefix}.#{expected_extension}" }
+ let(:expected_path) { File.join(storage_path, cache_key, expected_filename) }
+ let(:expected_prefix) { "gitlab-git-test-#{ref}-#{SeedRepo::LastCommit::ID}" }
- it 'returns parameterised string for a ref containing slashes' do
- prefix = repository.archive_prefix('test/branch', 'SHA')
+ subject(:metadata) { repository.archive_metadata(ref, storage_path, format, append_sha: append_sha) }
- expect(prefix).to eq("#{project_name}-test-branch-SHA")
+ it 'sets RepoPath to the repository path' do
+ expect(metadata['RepoPath']).to eq(repository.path)
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")
+ it 'sets CommitId to the commit SHA' do
+ expect(metadata['CommitId']).to eq(SeedRepo::LastCommit::ID)
end
- end
- describe '#archive' do
- let(:metadata) { repository.archive_metadata('master', '/tmp') }
+ it 'sets ArchivePrefix to the expected prefix' do
+ expect(metadata['ArchivePrefix']).to eq(expected_prefix)
+ end
- it_should_behave_like 'archive check', '.tar.gz'
- end
+ it 'sets ArchivePath to the expected globally-unique path' do
+ # This is really important from a security perspective. Think carefully
+ # before changing it: https://gitlab.com/gitlab-org/gitlab-ce/issues/45689
+ expect(expected_path).to include(File.join(repository.gl_repository, SeedRepo::LastCommit::ID))
- describe '#archive_zip' do
- let(:metadata) { repository.archive_metadata('master', '/tmp', 'zip') }
+ expect(metadata['ArchivePath']).to eq(expected_path)
+ end
- it_should_behave_like 'archive check', '.zip'
- end
+ context 'append_sha varies archive path and filename' do
+ where(:append_sha, :ref, :expected_prefix) do
+ sha = SeedRepo::LastCommit::ID
- describe '#archive_bz2' do
- let(:metadata) { repository.archive_metadata('master', '/tmp', 'tbz2') }
+ true | 'master' | "gitlab-git-test-master-#{sha}"
+ true | sha | "gitlab-git-test-#{sha}-#{sha}"
+ false | 'master' | "gitlab-git-test-master"
+ false | sha | "gitlab-git-test-#{sha}"
+ nil | 'master' | "gitlab-git-test-master-#{sha}"
+ nil | sha | "gitlab-git-test-#{sha}"
+ end
- it_should_behave_like 'archive check', '.tar.bz2'
- end
+ with_them do
+ it { expect(metadata['ArchivePrefix']).to eq(expected_prefix) }
+ it { expect(metadata['ArchivePath']).to eq(expected_path) }
+ end
+ end
- describe '#archive_fallback' do
- let(:metadata) { repository.archive_metadata('master', '/tmp', 'madeup') }
+ context 'format varies archive path and filename' do
+ where(:format, :expected_extension) do
+ nil | 'tar.gz'
+ 'madeup' | 'tar.gz'
+ 'tbz2' | 'tar.bz2'
+ 'zip' | 'zip'
+ end
- it_should_behave_like 'archive check', '.tar.gz'
+ with_them do
+ it { expect(metadata['ArchivePrefix']).to eq(expected_prefix) }
+ it { expect(metadata['ArchivePath']).to eq(expected_path) }
+ end
+ end
end
describe '#size' do
@@ -464,9 +483,20 @@ describe Gitlab::Git::Repository, seed_helper: true do
FileUtils.rm_rf(heads_dir)
FileUtils.mkdir_p(heads_dir)
+ repository.expire_has_local_branches_cache
expect(repository.has_local_branches?).to eq(false)
end
end
+
+ context 'memoizes the value' do
+ it 'returns true' do
+ expect(repository).to receive(:uncached_has_local_branches?).once.and_call_original
+
+ 2.times do
+ expect(repository.has_local_branches?).to eq(true)
+ end
+ end
+ end
end
context 'with gitaly' do
@@ -672,7 +702,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
after do
- Gitlab::Shell.new.remove_repository(storage_path, 'my_project')
+ Gitlab::Shell.new.remove_repository('default', 'my_project')
end
shared_examples 'repository mirror fecthing' do
@@ -1037,6 +1067,44 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.to eq(17) }
end
+ describe '#raw_changes_between' do
+ let(:old_rev) { }
+ let(:new_rev) { }
+ let(:changes) { repository.raw_changes_between(old_rev, new_rev) }
+
+ context 'initial commit' do
+ let(:old_rev) { Gitlab::Git::BLANK_SHA }
+ let(:new_rev) { '1a0b36b3cdad1d2ee32457c102a8c0b7056fa863' }
+
+ it 'returns the changes' do
+ expect(changes).to be_present
+ expect(changes.size).to eq(3)
+ end
+ end
+
+ context 'with an invalid rev' do
+ let(:old_rev) { 'foo' }
+ let(:new_rev) { 'bar' }
+
+ it 'returns an error' do
+ expect { changes }.to raise_error(Gitlab::Git::Repository::GitError)
+ end
+ end
+
+ context 'with valid revs' do
+ let(:old_rev) { 'fa1b1e6c004a68b7d8763b86455da9e6b23e36d6' }
+ let(:new_rev) { '4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6' }
+
+ it 'returns the changes' do
+ expect(changes.size).to eq(9)
+ expect(changes.first.operation).to eq(:modified)
+ expect(changes.first.new_path).to eq('.gitmodules')
+ expect(changes.last.operation).to eq(:added)
+ expect(changes.last.new_path).to eq('files/lfs/picture-invalid.png')
+ end
+ end
+ end
+
describe '#merge_base' do
shared_examples '#merge_base' do
where(:from, :to, :result) do
@@ -2178,6 +2246,55 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#checksum' do
+ shared_examples 'calculating checksum' do
+ it 'calculates the checksum for non-empty repo' do
+ expect(repository.checksum).to eq '54f21be4c32c02f6788d72207fa03ad3bce725e4'
+ end
+
+ it 'returns 0000000000000000000000000000000000000000 for an empty repo' do
+ FileUtils.rm_rf(File.join(storage_path, 'empty-repo.git'))
+
+ system(git_env, *%W(#{Gitlab.config.git.bin_path} init --bare empty-repo.git),
+ chdir: storage_path,
+ out: '/dev/null',
+ err: '/dev/null')
+
+ empty_repo = described_class.new('default', 'empty-repo.git', '')
+
+ expect(empty_repo.checksum).to eq '0000000000000000000000000000000000000000'
+ end
+
+ it 'raises a no repository exception when there is no repo' do
+ broken_repo = described_class.new('default', 'a/path.git', '')
+
+ expect { broken_repo.checksum }.to raise_error(Gitlab::Git::Repository::NoRepository)
+ end
+ end
+
+ context 'when calculate_checksum Gitaly feature is enabled' do
+ it_behaves_like 'calculating checksum'
+ end
+
+ context 'when calculate_checksum Gitaly feature is disabled', :disable_gitaly do
+ it_behaves_like 'calculating checksum'
+
+ describe 'when storage is broken', :broken_storage do
+ it 'raises a storage exception when storage is not available' do
+ broken_repo = described_class.new('broken', 'a/path.git', '')
+
+ expect { broken_repo.rugged }.to raise_error(Gitlab::Git::Storage::Inaccessible)
+ end
+ end
+
+ it "raises a Gitlab::Git::Repository::Failure error if the `popen` call to git returns a non-zero exit code" do
+ allow(repository).to receive(:popen).and_return(['output', nil])
+
+ expect { repository.checksum }.to raise_error Gitlab::Git::Repository::ChecksumError
+ end
+ end
+ end
+
context 'gitlab_projects commands' do
let(:gitlab_projects) { repository.gitlab_projects }
let(:timeout) { Gitlab.config.gitlab_shell.git_timeout }
@@ -2251,6 +2368,39 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#clean_stale_repository_files' do
+ let(:worktree_path) { File.join(repository.path, 'worktrees', 'delete-me') }
+
+ it 'cleans up the files' do
+ repository.with_worktree(worktree_path, 'master', env: ENV) do
+ FileUtils.touch(worktree_path, mtime: Time.now - 8.hours)
+ # git rev-list --all will fail in git 2.16 if HEAD is pointing to a non-existent object,
+ # but the HEAD must be 40 characters long or git will ignore it.
+ File.write(File.join(worktree_path, 'HEAD'), Gitlab::Git::BLANK_SHA)
+
+ # git 2.16 fails with "fatal: bad object HEAD"
+ expect { repository.rev_list(including: :all) }.to raise_error(Gitlab::Git::Repository::GitError)
+
+ repository.clean_stale_repository_files
+
+ expect { repository.rev_list(including: :all) }.not_to raise_error
+ expect(File.exist?(worktree_path)).to be_falsey
+ end
+ end
+
+ it 'increments a counter upon an error' do
+ expect(repository.gitaly_repository_client).to receive(:cleanup).and_raise(Gitlab::Git::CommandError)
+
+ counter = double(:counter)
+
+ expect(counter).to receive(:increment)
+ expect(Gitlab::Metrics).to receive(:counter).with(:failed_repository_cleanup_total,
+ 'Number of failed repository cleanup events').and_return(counter)
+
+ repository.clean_stale_repository_files
+ end
+ end
+
describe '#delete_remote_branches' do
subject do
repository.delete_remote_branches('downstream-remote', ['master'])
diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb
index 761f7732036..722d697c28e 100644
--- a/spec/lib/gitlab/git/wiki_spec.rb
+++ b/spec/lib/gitlab/git/wiki_spec.rb
@@ -30,7 +30,7 @@ describe Gitlab::Git::Wiki do
end
def commit_details(name)
- Gitlab::Git::Wiki::CommitDetails.new(user.name, user.email, "created page #{name}")
+ Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "created page #{name}")
end
def destroy_page(title, dir = '')
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index f8f09d29c73..6c625596605 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -10,12 +10,13 @@ describe Gitlab::GitAccess do
let(:protocol) { 'ssh' }
let(:authentication_abilities) { %i[read_project download_code push_code] }
let(:redirected_path) { nil }
+ let(:auth_result_type) { nil }
let(:access) do
described_class.new(actor, project,
protocol, authentication_abilities: authentication_abilities,
namespace_path: namespace_path, project_path: project_path,
- redirected_path: redirected_path)
+ redirected_path: redirected_path, auth_result_type: auth_result_type)
end
let(:changes) { '_any' }
@@ -45,6 +46,7 @@ describe Gitlab::GitAccess do
before do
disable_protocol('http')
+ project.add_master(user)
end
it 'blocks http push and pull' do
@@ -53,6 +55,26 @@ describe Gitlab::GitAccess do
expect { pull_access_check }.to raise_unauthorized('Git access over HTTP is not allowed')
end
end
+
+ context 'when request is made from CI' do
+ let(:auth_result_type) { :build }
+
+ it "doesn't block http pull" do
+ aggregate_failures do
+ expect { pull_access_check }.not_to raise_unauthorized('Git access over HTTP is not allowed')
+ end
+ end
+
+ context 'when legacy CI credentials are used' do
+ let(:auth_result_type) { :ci }
+
+ it "doesn't block http pull" do
+ aggregate_failures do
+ expect { pull_access_check }.not_to raise_unauthorized('Git access over HTTP is not allowed')
+ end
+ end
+ end
+ end
end
end
@@ -123,6 +145,33 @@ describe Gitlab::GitAccess do
expect { push_access_check }.to raise_unauthorized(described_class::ERROR_MESSAGES[:auth_upload])
end
end
+
+ context 'when actor is DeployToken' do
+ let(:actor) { create(:deploy_token, projects: [project]) }
+
+ context 'when DeployToken is active and belongs to project' do
+ it 'allows pull access' do
+ expect { pull_access_check }.not_to raise_error
+ end
+
+ it 'blocks the push' do
+ expect { push_access_check }.to raise_unauthorized(described_class::ERROR_MESSAGES[:upload])
+ end
+ end
+
+ context 'when DeployToken does not belong to project' do
+ let(:another_project) { create(:project) }
+ let(:actor) { create(:deploy_token, projects: [another_project]) }
+
+ it 'blocks pull access' do
+ expect { pull_access_check }.to raise_not_found
+ end
+
+ it 'blocks the push' do
+ expect { push_access_check }.to raise_not_found
+ end
+ end
+ end
end
context 'when actor is nil' do
@@ -572,6 +621,41 @@ describe Gitlab::GitAccess do
end
end
+ describe 'deploy token permissions' do
+ let(:deploy_token) { create(:deploy_token) }
+ let(:actor) { deploy_token }
+
+ context 'pull code' do
+ context 'when project is authorized' do
+ before do
+ deploy_token.projects << project
+ end
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'when unauthorized' do
+ context 'from public project' do
+ let(:project) { create(:project, :public, :repository) }
+
+ it { expect { pull_access_check }.not_to raise_error }
+ end
+
+ context 'from internal project' do
+ let(:project) { create(:project, :internal, :repository) }
+
+ it { expect { pull_access_check }.to raise_not_found }
+ end
+
+ context 'from private project' do
+ let(:project) { create(:project, :private, :repository) }
+
+ it { expect { pull_access_check }.to raise_not_found }
+ end
+ end
+ end
+ end
+
describe 'build authentication_abilities permissions' do
let(:authentication_abilities) { build_authentication_abilities }
@@ -833,6 +917,20 @@ describe Gitlab::GitAccess do
admin: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false }))
end
end
+
+ context 'when pushing to a project' do
+ let(:project) { create(:project, :public, :repository) }
+ let(:changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow" }
+
+ before do
+ project.add_developer(user)
+ end
+
+ it 'cleans up the files' do
+ expect(project.repository).to receive(:clean_stale_repository_files).and_call_original
+ expect { push_access_check }.not_to raise_error
+ end
+ end
end
describe 'build authentication abilities' do
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 9be3fa633a7..7951cbe7b1d 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -33,7 +33,7 @@ describe Gitlab::GitalyClient::CommitService do
initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863').raw
request = Gitaly::CommitDiffRequest.new(
repository: repository_message,
- left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
+ left_commit_id: Gitlab::Git::EMPTY_TREE_ID,
right_commit_id: initial_commit.id,
collapse_diffs: true,
enforce_limits: true,
@@ -77,7 +77,7 @@ describe Gitlab::GitalyClient::CommitService do
initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863')
request = Gitaly::CommitDeltaRequest.new(
repository: repository_message,
- left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904',
+ left_commit_id: Gitlab::Git::EMPTY_TREE_ID,
right_commit_id: initial_commit.id
)
@@ -90,7 +90,7 @@ describe Gitlab::GitalyClient::CommitService do
describe '#between' do
let(:from) { 'master' }
- let(:to) { '4b825dc642cb6eb9a060e54bf8d69288fbee4904' }
+ let(:to) { Gitlab::Git::EMPTY_TREE_ID }
it 'sends an RPC request' do
request = Gitaly::CommitsBetweenRequest.new(
@@ -155,7 +155,7 @@ describe Gitlab::GitalyClient::CommitService do
end
describe '#find_commit' do
- let(:revision) { '4b825dc642cb6eb9a060e54bf8d69288fbee4904' }
+ let(:revision) { Gitlab::Git::EMPTY_TREE_ID }
it 'sends an RPC request' do
request = Gitaly::FindCommitRequest.new(
repository: repository_message, revision: revision
diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
index 1c41dbcb9ef..ecd8657c406 100644
--- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb
@@ -17,6 +17,16 @@ describe Gitlab::GitalyClient::RepositoryService do
end
end
+ describe '#cleanup' do
+ it 'sends a cleanup message' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:cleanup)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+
+ client.cleanup
+ end
+ end
+
describe '#garbage_collect' do
it 'sends a garbage_collect message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
@@ -74,6 +84,17 @@ describe Gitlab::GitalyClient::RepositoryService do
end
end
+ describe '#info_attributes' do
+ it 'reads the info attributes' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:get_info_attributes)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return([])
+
+ client.info_attributes
+ end
+ end
+
describe '#has_local_branches?' do
it 'sends a has_local_branches message' do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
@@ -124,4 +145,26 @@ describe Gitlab::GitalyClient::RepositoryService do
client.squash_in_progress?(squash_id)
end
end
+
+ describe '#calculate_checksum' do
+ it 'sends a calculate_checksum message' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:calculate_checksum)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double(checksum: 0))
+
+ client.calculate_checksum
+ end
+ end
+
+ describe '#create_from_snapshot' do
+ it 'sends a create_repository_from_snapshot message' do
+ expect_any_instance_of(Gitaly::RepositoryService::Stub)
+ .to receive(:create_repository_from_snapshot)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double)
+
+ client.create_from_snapshot('http://example.com?wiki=1', 'Custom xyz')
+ end
+ end
end
diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
index 82548c7fd31..5ea086e4abd 100644
--- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb
@@ -12,7 +12,7 @@ describe Gitlab::GitlabImport::ProjectCreator do
owner: { name: "john" }
}.with_indifferent_access
end
- let(:namespace) { create(:group, owner: user) }
+ let(:namespace) { create(:group) }
let(:token) { "asdffg" }
let(:access_params) { { gitlab_access_token: token } }
diff --git a/spec/lib/gitlab/google_code_import/project_creator_spec.rb b/spec/lib/gitlab/google_code_import/project_creator_spec.rb
index 8d5b60d50de..24cd518c77b 100644
--- a/spec/lib/gitlab/google_code_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/google_code_import/project_creator_spec.rb
@@ -9,7 +9,7 @@ describe Gitlab::GoogleCodeImport::ProjectCreator do
"repositoryUrls" => ["https://vim.googlecode.com/git/"]
)
end
- let(:namespace) { create(:group, owner: user) }
+ let(:namespace) { create(:group) }
before do
namespace.add_owner(user)
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index b675d5dc031..dd5640dd9de 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -145,6 +145,9 @@ pipeline_schedule:
- pipelines
pipeline_schedule_variables:
- pipeline_schedule
+deploy_tokens:
+- project_deploy_tokens
+- projects
deploy_keys:
- user
- deploy_keys_projects
@@ -255,7 +258,6 @@ project:
- builds
- runner_projects
- runners
-- active_runners
- variables
- triggers
- pipeline_schedules
@@ -281,6 +283,10 @@ project:
- project_badges
- source_of_merge_requests
- internal_ids
+- project_deploy_tokens
+- deploy_tokens
+- settings
+- ci_cd_settings
award_emoji:
- awardable
- user
diff --git a/spec/lib/gitlab/import_export/importer_spec.rb b/spec/lib/gitlab/import_export/importer_spec.rb
new file mode 100644
index 00000000000..991e354f499
--- /dev/null
+++ b/spec/lib/gitlab/import_export/importer_spec.rb
@@ -0,0 +1,104 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::Importer do
+ let(:user) { create(:user) }
+ let(:test_path) { "#{Dir.tmpdir}/importer_spec" }
+ let(:shared) { project.import_export_shared }
+ let(:project) { create(:project, import_source: File.join(test_path, 'exported-project.gz')) }
+
+ subject(:importer) { described_class.new(project) }
+
+ before do
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(test_path)
+ FileUtils.mkdir_p(shared.export_path)
+ FileUtils.cp(Rails.root.join('spec', 'fixtures', 'exported-project.gz'), test_path)
+ allow(subject).to receive(:remove_import_file)
+ end
+
+ after do
+ FileUtils.rm_rf(test_path)
+ end
+
+ describe '#execute' do
+ it 'succeeds' do
+ importer.execute
+
+ expect(shared.errors).to be_empty
+ end
+
+ it 'extracts the archive' do
+ expect(Gitlab::ImportExport::FileImporter).to receive(:import).and_call_original
+
+ importer.execute
+ end
+
+ it 'checks the version' do
+ expect(Gitlab::ImportExport::VersionChecker).to receive(:check!).and_call_original
+
+ importer.execute
+ end
+
+ context 'all restores are executed' do
+ [
+ Gitlab::ImportExport::AvatarRestorer,
+ Gitlab::ImportExport::RepoRestorer,
+ Gitlab::ImportExport::WikiRestorer,
+ Gitlab::ImportExport::UploadsRestorer,
+ Gitlab::ImportExport::LfsRestorer,
+ Gitlab::ImportExport::StatisticsRestorer
+ ].each do |restorer|
+ it "calls the #{restorer}" do
+ fake_restorer = double(restorer.to_s)
+
+ expect(fake_restorer).to receive(:restore).and_return(true).at_least(1)
+ expect(restorer).to receive(:new).and_return(fake_restorer).at_least(1)
+
+ importer.execute
+ end
+ end
+
+ it 'restores the ProjectTree' do
+ expect(Gitlab::ImportExport::ProjectTreeRestorer).to receive(:new).and_call_original
+
+ importer.execute
+ end
+ end
+
+ context 'when project successfully restored' do
+ let!(:existing_project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:project, namespace: user.namespace, name: 'whatever', path: 'whatever') }
+
+ before do
+ restorers = double
+
+ allow(subject).to receive(:import_file).and_return(true)
+ allow(subject).to receive(:check_version!).and_return(true)
+ allow(subject).to receive(:restorers).and_return(restorers)
+ allow(restorers).to receive(:all?).and_return(true)
+ allow(project).to receive(:import_data).and_return(double(data: { 'original_path' => existing_project.path }))
+ end
+
+ context 'when import_data' do
+ context 'has original_path' do
+ it 'overwrites existing project' do
+ expect_any_instance_of(::Projects::OverwriteProjectService).to receive(:execute).with(existing_project)
+
+ subject.execute
+ end
+ end
+
+ context 'has not original_path' do
+ before do
+ allow(project).to receive(:import_data).and_return(double(data: {}))
+ end
+
+ it 'does not call the overwrite service' do
+ expect_any_instance_of(::Projects::OverwriteProjectService).not_to receive(:execute).with(existing_project)
+
+ subject.execute
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/lfs_restorer_spec.rb b/spec/lib/gitlab/import_export/lfs_restorer_spec.rb
new file mode 100644
index 00000000000..70eeb9ee66b
--- /dev/null
+++ b/spec/lib/gitlab/import_export/lfs_restorer_spec.rb
@@ -0,0 +1,75 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::LfsRestorer do
+ include UploadHelpers
+
+ let(:export_path) { "#{Dir.tmpdir}/lfs_object_restorer_spec" }
+ let(:project) { create(:project) }
+ let(:shared) { project.import_export_shared }
+ subject(:restorer) { described_class.new(project: project, shared: shared) }
+
+ before do
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+ FileUtils.mkdir_p(shared.export_path)
+ end
+
+ after do
+ FileUtils.rm_rf(shared.export_path)
+ end
+
+ describe '#restore' do
+ context 'when the archive contains lfs files' do
+ let(:dummy_lfs_file_path) { File.join(shared.export_path, 'lfs-objects', 'dummy') }
+
+ def create_lfs_object_with_content(content)
+ dummy_lfs_file = Tempfile.new('existing')
+ File.write(dummy_lfs_file.path, content)
+ size = dummy_lfs_file.size
+ oid = LfsObject.calculate_oid(dummy_lfs_file.path)
+ LfsObject.create!(oid: oid, size: size, file: dummy_lfs_file)
+ end
+
+ before do
+ FileUtils.mkdir_p(File.dirname(dummy_lfs_file_path))
+ File.write(dummy_lfs_file_path, 'not very large')
+ allow(restorer).to receive(:lfs_file_paths).and_return([dummy_lfs_file_path])
+ end
+
+ it 'creates an lfs object for the project' do
+ expect { restorer.restore }.to change { project.reload.lfs_objects.size }.by(1)
+ end
+
+ it 'assigns the file correctly' do
+ restorer.restore
+
+ expect(project.lfs_objects.first.file.read).to eq('not very large')
+ end
+
+ it 'links an existing LFS object if it existed' do
+ lfs_object = create_lfs_object_with_content('not very large')
+
+ restorer.restore
+
+ expect(project.lfs_objects).to include(lfs_object)
+ end
+
+ it 'succeeds' do
+ expect(restorer.restore).to be_truthy
+ expect(shared.errors).to be_empty
+ end
+
+ it 'stores the upload' do
+ expect_any_instance_of(LfsObjectUploader).to receive(:store!)
+
+ restorer.restore
+ end
+ end
+
+ context 'without any LFS-objects' do
+ it 'succeeds' do
+ expect(restorer.restore).to be_truthy
+ expect(shared.errors).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/lfs_saver_spec.rb b/spec/lib/gitlab/import_export/lfs_saver_spec.rb
new file mode 100644
index 00000000000..9b0e21deb2e
--- /dev/null
+++ b/spec/lib/gitlab/import_export/lfs_saver_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::LfsSaver do
+ let(:shared) { project.import_export_shared }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let(:project) { create(:project) }
+
+ subject(:saver) { described_class.new(project: project, shared: shared) }
+
+ before do
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+ FileUtils.mkdir_p(shared.export_path)
+ end
+
+ after do
+ FileUtils.rm_rf(shared.export_path)
+ end
+
+ describe '#save' do
+ context 'when the project has LFS objects locally stored' do
+ let(:lfs_object) { create(:lfs_object, :with_file) }
+
+ before do
+ project.lfs_objects << lfs_object
+ end
+
+ it 'does not cause errors' do
+ saver.save
+
+ expect(shared.errors).to be_empty
+ end
+
+ it 'copies the file in the correct location when there is an lfs object' do
+ saver.save
+
+ expect(File).to exist("#{shared.export_path}/lfs-objects/#{lfs_object.oid}")
+ end
+ end
+
+ context 'when the LFS objects are stored in object storage' do
+ let(:lfs_object) { create(:lfs_object, :object_storage) }
+
+ before do
+ allow(LfsObjectUploader).to receive(:object_store_enabled?).and_return(true)
+ allow(lfs_object.file).to receive(:url).and_return('http://my-object-storage.local')
+ project.lfs_objects << lfs_object
+ end
+
+ it 'downloads the file to include in an archive' do
+ fake_uri = double
+ exported_file_path = "#{shared.export_path}/lfs-objects/#{lfs_object.oid}"
+
+ expect(fake_uri).to receive(:open).and_return(StringIO.new('LFS file content'))
+ expect(URI).to receive(:parse).with('http://my-object-storage.local').and_return(fake_uri)
+
+ saver.save
+
+ expect(File.read(exported_file_path)).to eq('LFS file content')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 4a51777ba9b..6d63749296e 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2,7 +2,6 @@
"description": "Nisi et repellendus ut enim quo accusamus vel magnam.",
"visibility_level": 10,
"archived": false,
- "description_html": "description",
"labels": [
{
"id": 2,
@@ -6181,12 +6180,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
"erased_by_id": null,
"erased_at": null,
"type": "Ci::Build",
@@ -6219,12 +6212,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
}
@@ -6293,12 +6280,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
},
@@ -6328,12 +6309,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
"erased_by_id": null,
"erased_at": null
}
@@ -6393,12 +6368,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
},
@@ -6428,12 +6397,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
}
@@ -6493,12 +6456,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
},
@@ -6528,12 +6485,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
}
@@ -6593,12 +6544,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
"erased_by_id": null,
"erased_at": null
},
@@ -6628,12 +6573,6 @@
"user_id": null,
"target_url": null,
"description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz"
- },
"erased_by_id": null,
"erased_at": null
}
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 8e25cd26c2f..13a8c9adcee 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -46,10 +46,6 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
expect(Project.find_by_path('project').description).to eq('Nisi et repellendus ut enim quo accusamus vel magnam.')
end
- it 'has the project html description' do
- expect(Project.find_by_path('project').description_html).to eq('description')
- end
-
it 'has the same label associated to two issues' do
expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2)
end
@@ -317,6 +313,24 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
end
+ context 'when the project has overriden params in import data' do
+ it 'overwrites the params stored in the JSON' do
+ project.create_import_data(data: { override_params: { description: "Overridden" } })
+
+ restored_project_json
+
+ expect(project.description).to eq("Overridden")
+ end
+
+ it 'does not allow setting params that are excluded from import_export settings' do
+ project.create_import_data(data: { override_params: { lfs_enabled: true } })
+
+ restored_project_json
+
+ expect(project.lfs_enabled).to be_nil
+ end
+ end
+
context 'with a project that has a group' do
let!(:project) do
create(:project,
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 0d20a551e2a..2b8a11ce8f9 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -245,10 +245,6 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
end
context 'project attributes' do
- it 'contains the html description' do
- expect(saved_project_json).to include("description_html" => 'description')
- end
-
it 'does not contain the runners token' do
expect(saved_project_json).not_to include("runners_token" => 'token')
end
@@ -274,7 +270,6 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
releases: [release],
group: group
)
- project.update_column(:description_html, 'description')
project_label = create(:label, project: project)
group_label = create(:group_label, group: group)
create(:label_link, label: project_label, target: issue)
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index f949a23ffbb..62da967cf96 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -232,6 +232,7 @@ Ci::Stage:
- id
- name
- status
+- position
- lock_version
- project_id
- pipeline_id
@@ -390,6 +391,7 @@ Service:
- default
- wiki_page_events
- confidential_issues_events
+- confidential_note_events
ProjectHook:
- id
- url
@@ -410,6 +412,7 @@ ProjectHook:
- token
- group_id
- confidential_issues_events
+- confidential_note_events
- repository_update_events
ProtectedBranch:
- id
@@ -535,12 +538,6 @@ ProjectCustomAttribute:
- project_id
- key
- value
-LfsFileLock:
-- id
-- path
-- user_id
-- project_id
-- created_at
Badge:
- id
- link_url
@@ -550,3 +547,5 @@ Badge:
- created_at
- updated_at
- type
+ProjectCiCdSetting:
+- group_runners_enabled
diff --git a/spec/lib/gitlab/import_export/wiki_restorer_spec.rb b/spec/lib/gitlab/import_export/wiki_restorer_spec.rb
index 5c01ee0ebb8..f99f198da33 100644
--- a/spec/lib/gitlab/import_export/wiki_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_restorer_spec.rb
@@ -24,8 +24,8 @@ describe Gitlab::ImportExport::WikiRestorer do
after do
FileUtils.rm_rf(export_path)
- Gitlab::Shell.new.remove_repository(project_with_wiki.wiki.repository_storage_path, project_with_wiki.wiki.disk_path)
- Gitlab::Shell.new.remove_repository(project.wiki.repository_storage_path, project.wiki.disk_path)
+ Gitlab::Shell.new.remove_repository(project_with_wiki.wiki.repository_storage, project_with_wiki.wiki.disk_path)
+ Gitlab::Shell.new.remove_repository(project.wiki.repository_storage, project.wiki.disk_path)
end
it 'restores the wiki repo successfully' do
diff --git a/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb
index 3cfdae794f6..7be8be54d5e 100644
--- a/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb
@@ -4,22 +4,10 @@ describe Gitlab::Kubernetes::Helm::BaseCommand do
let(:application) { create(:clusters_applications_helm) }
let(:base_command) { described_class.new(application.name) }
- describe '#generate_script' do
- let(:helm_version) { Gitlab::Kubernetes::Helm::HELM_VERSION }
- let(:command) do
- <<~HEREDOC
- set -eo pipefail
- apk add -U ca-certificates openssl >/dev/null
- wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{helm_version}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
- mv /tmp/linux-amd64/helm /usr/bin/
- HEREDOC
- end
-
- subject { base_command.generate_script }
+ subject { base_command }
- it 'should return a command that prepares the environment for helm-cli' do
- expect(subject).to eq(command)
- end
+ it_behaves_like 'helm commands' do
+ let(:commands) { '' }
end
describe '#pod_resource' do
diff --git a/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb
index e6920b0a76f..89e36a298f8 100644
--- a/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb
@@ -2,23 +2,9 @@ require 'spec_helper'
describe Gitlab::Kubernetes::Helm::InitCommand do
let(:application) { create(:clusters_applications_helm) }
- let(:init_command) { described_class.new(application.name) }
+ let(:commands) { 'helm init >/dev/null' }
- describe '#generate_script' do
- let(:command) do
- <<~MSG.chomp
- set -eo pipefail
- apk add -U ca-certificates openssl >/dev/null
- wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
- mv /tmp/linux-amd64/helm /usr/bin/
- helm init >/dev/null
- MSG
- end
+ subject { described_class.new(application.name) }
- subject { init_command.generate_script }
-
- it 'should return the appropriate command' do
- is_expected.to eq(command)
- end
- end
+ it_behaves_like 'helm commands'
end
diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
index 137b8f718de..547f3f1752c 100644
--- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -12,50 +12,36 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
)
end
- describe '#generate_script' do
- let(:command) do
- <<~MSG
- set -eo pipefail
- apk add -U ca-certificates openssl >/dev/null
- wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
- mv /tmp/linux-amd64/helm /usr/bin/
- helm init --client-only >/dev/null
- helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
- MSG
- end
-
- subject { install_command.generate_script }
+ subject { install_command }
- it 'should return appropriate command' do
- is_expected.to eq(command)
+ it_behaves_like 'helm commands' do
+ let(:commands) do
+ <<~EOS
+ helm init --client-only >/dev/null
+ helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
+ EOS
end
+ end
- context 'with an application with a repository' do
- let(:ci_runner) { create(:ci_runner) }
- let(:application) { create(:clusters_applications_runner, runner: ci_runner) }
- let(:install_command) do
- described_class.new(
- application.name,
- chart: application.chart,
- values: application.values,
- repository: application.repository
- )
- end
-
- let(:command) do
- <<~MSG
- set -eo pipefail
- apk add -U ca-certificates openssl >/dev/null
- wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
- mv /tmp/linux-amd64/helm /usr/bin/
- helm init --client-only >/dev/null
- helm repo add #{application.name} #{application.repository}
- helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
- MSG
- end
+ context 'with an application with a repository' do
+ let(:ci_runner) { create(:ci_runner) }
+ let(:application) { create(:clusters_applications_runner, runner: ci_runner) }
+ let(:install_command) do
+ described_class.new(
+ application.name,
+ chart: application.chart,
+ values: application.values,
+ repository: application.repository
+ )
+ end
- it 'should return appropriate command' do
- is_expected.to eq(command)
+ it_behaves_like 'helm commands' do
+ let(:commands) do
+ <<~EOS
+ helm init --client-only >/dev/null
+ helm repo add #{application.name} #{application.repository}
+ helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
+ EOS
end
end
end
diff --git a/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb b/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
index 737c9a624e0..eb1b13704ea 100644
--- a/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::LegacyGithubImport::ProjectCreator do
let(:user) { create(:user) }
- let(:namespace) { create(:group, owner: user) }
+ let(:namespace) { create(:group) }
let(:repo) do
OpenStruct.new(
diff --git a/spec/lib/gitlab/pages_client_spec.rb b/spec/lib/gitlab/pages_client_spec.rb
new file mode 100644
index 00000000000..da6d26f4aee
--- /dev/null
+++ b/spec/lib/gitlab/pages_client_spec.rb
@@ -0,0 +1,172 @@
+require 'spec_helper'
+
+describe Gitlab::PagesClient do
+ subject { described_class }
+
+ describe '.token' do
+ it 'returns the token as it is on disk' do
+ pending 'add omnibus support for generating the secret file https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/2466'
+ expect(subject.token).to eq(File.read('.gitlab_pages_secret'))
+ end
+ end
+
+ describe '.read_or_create_token' do
+ subject { described_class.read_or_create_token }
+ let(:token_path) { 'tmp/tests/gitlab-pages-secret' }
+ before do
+ allow(described_class).to receive(:token_path).and_return(token_path)
+ FileUtils.rm_f(token_path)
+ end
+
+ it 'uses the existing token file if it exists' do
+ secret = 'existing secret'
+ File.write(token_path, secret)
+
+ subject
+ expect(described_class.token).to eq(secret)
+ end
+
+ it 'creates one if none exists' do
+ pending 'add omnibus support for generating the secret file https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/2466'
+
+ old_token = described_class.token
+ # sanity check
+ expect(File.exist?(token_path)).to eq(false)
+
+ subject
+ expect(described_class.token.bytesize).to eq(64)
+ expect(described_class.token).not_to eq(old_token)
+ end
+ end
+
+ describe '.write_token' do
+ let(:token_path) { 'tmp/tests/gitlab-pages-secret' }
+ before do
+ allow(described_class).to receive(:token_path).and_return(token_path)
+ FileUtils.rm_f(token_path)
+ end
+
+ it 'writes the secret' do
+ new_secret = 'hello new secret'
+ expect(File.exist?(token_path)).to eq(false)
+
+ described_class.send(:write_token, new_secret)
+
+ expect(File.read(token_path)).to eq(new_secret)
+ end
+
+ it 'does nothing if the file already exists' do
+ existing_secret = 'hello secret'
+ File.write(token_path, existing_secret)
+
+ described_class.send(:write_token, 'new secret')
+
+ expect(File.read(token_path)).to eq(existing_secret)
+ end
+ end
+
+ describe '.load_certificate' do
+ subject { described_class.load_certificate }
+ before do
+ allow(described_class).to receive(:config).and_return(config)
+ end
+
+ context 'with no certificate in the config' do
+ let(:config) { double(:config, certificate: '') }
+
+ it 'does not set @certificate' do
+ subject
+
+ expect(described_class.certificate).to be_nil
+ end
+ end
+
+ context 'with a certificate path in the config' do
+ let(:certificate_path) { 'tmp/tests/fake-certificate' }
+ let(:config) { double(:config, certificate: certificate_path) }
+
+ it 'sets @certificate' do
+ certificate_data = "--- BEGIN CERTIFICATE ---\nbla\n--- END CERTIFICATE ---\n"
+ File.write(certificate_path, certificate_data)
+ subject
+
+ expect(described_class.certificate).to eq(certificate_data)
+ end
+ end
+ end
+
+ describe '.request_kwargs' do
+ let(:token) { 'secret token' }
+ let(:auth_header) { 'Bearer c2VjcmV0IHRva2Vu' }
+ before do
+ allow(described_class).to receive(:token).and_return(token)
+ end
+
+ context 'without timeout' do
+ it { expect(subject.send(:request_kwargs, nil)[:metadata]['authorization']).to eq(auth_header) }
+ end
+
+ context 'with timeout' do
+ let(:timeout) { 1.second }
+
+ it 'still sets the authorization header' do
+ expect(subject.send(:request_kwargs, timeout)[:metadata]['authorization']).to eq(auth_header)
+ end
+
+ it 'sets a deadline value' do
+ now = Time.now
+ deadline = subject.send(:request_kwargs, timeout)[:deadline]
+
+ expect(deadline).to be_between(now, now + 2 * timeout)
+ end
+ end
+ end
+
+ describe '.stub' do
+ before do
+ allow(described_class).to receive(:address).and_return('unix:/foo/bar')
+ end
+
+ it { expect(subject.send(:stub, :health_check)).to be_a(Grpc::Health::V1::Health::Stub) }
+ end
+
+ describe '.address' do
+ subject { described_class.send(:address) }
+
+ before do
+ allow(described_class).to receive(:config).and_return(config)
+ end
+
+ context 'with a unix: address' do
+ let(:config) { double(:config, address: 'unix:/foo/bar') }
+
+ it { expect(subject).to eq('unix:/foo/bar') }
+ end
+
+ context 'with a tcp:// address' do
+ let(:config) { double(:config, address: 'tcp://localhost:1234') }
+
+ it { expect(subject).to eq('localhost:1234') }
+ end
+ end
+
+ describe '.grpc_creds' do
+ subject { described_class.send(:grpc_creds) }
+
+ before do
+ allow(described_class).to receive(:config).and_return(config)
+ end
+
+ context 'with a unix: address' do
+ let(:config) { double(:config, address: 'unix:/foo/bar') }
+
+ it { expect(subject).to eq(:this_channel_is_insecure) }
+ end
+
+ context 'with a tcp:// address' do
+ let(:config) { double(:config, address: 'tcp://localhost:1234') }
+
+ it { expect(subject).to be_a(GRPC::Core::ChannelCredentials) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sentry_spec.rb b/spec/lib/gitlab/sentry_spec.rb
index 8c211d1c63f..499757da061 100644
--- a/spec/lib/gitlab/sentry_spec.rb
+++ b/spec/lib/gitlab/sentry_spec.rb
@@ -7,7 +7,49 @@ describe Gitlab::Sentry do
described_class.context(nil)
- expect(Raven.tags_context[:locale]).to eq(I18n.locale.to_s)
+ expect(Raven.tags_context[:locale].to_s).to eq(I18n.locale.to_s)
+ end
+ end
+
+ describe '.track_exception' do
+ let(:exception) { RuntimeError.new('boom') }
+
+ before do
+ allow(described_class).to receive(:enabled?).and_return(true)
+ end
+
+ it 'raises the exception if it should' do
+ expect(described_class).to receive(:should_raise?).and_return(true)
+ expect { described_class.track_exception(exception) }
+ .to raise_error(RuntimeError)
+ end
+
+ context 'when exceptions should not be raised' do
+ before do
+ allow(described_class).to receive(:should_raise?).and_return(false)
+ end
+
+ it 'logs the exception with all attributes passed' do
+ expected_extras = {
+ some_other_info: 'info',
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1'
+ }
+
+ expect(Raven).to receive(:capture_exception)
+ .with(exception, extra: a_hash_including(expected_extras))
+
+ described_class.track_exception(
+ exception,
+ issue_url: 'http://gitlab.com/gitlab-org/gitlab-ce/issues/1',
+ extra: { some_other_info: 'info' }
+ )
+ end
+
+ it 'sets the context' do
+ expect(described_class).to receive(:context)
+
+ described_class.track_exception(exception)
+ end
end
end
end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 7ff2c0639ec..bf6ee4b0b59 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -447,18 +447,18 @@ describe Gitlab::Shell do
let(:disk_path) { "#{project.disk_path}.git" }
it 'returns true when the command succeeds' do
- expect(gitlab_shell.exists?(project.repository_storage_path, disk_path)).to be(true)
+ expect(gitlab_shell.exists?(project.repository_storage, disk_path)).to be(true)
- expect(gitlab_shell.remove_repository(project.repository_storage_path, project.disk_path)).to be(true)
+ expect(gitlab_shell.remove_repository(project.repository_storage, project.disk_path)).to be(true)
- expect(gitlab_shell.exists?(project.repository_storage_path, disk_path)).to be(false)
+ expect(gitlab_shell.exists?(project.repository_storage, disk_path)).to be(false)
end
it 'keeps the namespace directory' do
- gitlab_shell.remove_repository(project.repository_storage_path, project.disk_path)
+ gitlab_shell.remove_repository(project.repository_storage, project.disk_path)
- expect(gitlab_shell.exists?(project.repository_storage_path, disk_path)).to be(false)
- expect(gitlab_shell.exists?(project.repository_storage_path, project.disk_path.gsub(project.name, ''))).to be(true)
+ expect(gitlab_shell.exists?(project.repository_storage, disk_path)).to be(false)
+ expect(gitlab_shell.exists?(project.repository_storage, project.disk_path.gsub(project.name, ''))).to be(true)
end
end
@@ -469,18 +469,18 @@ describe Gitlab::Shell do
old_path = project2.disk_path
new_path = "project/new_path"
- expect(gitlab_shell.exists?(project2.repository_storage_path, "#{old_path}.git")).to be(true)
- expect(gitlab_shell.exists?(project2.repository_storage_path, "#{new_path}.git")).to be(false)
+ expect(gitlab_shell.exists?(project2.repository_storage, "#{old_path}.git")).to be(true)
+ expect(gitlab_shell.exists?(project2.repository_storage, "#{new_path}.git")).to be(false)
- expect(gitlab_shell.mv_repository(project2.repository_storage_path, old_path, new_path)).to be_truthy
+ expect(gitlab_shell.mv_repository(project2.repository_storage, old_path, new_path)).to be_truthy
- expect(gitlab_shell.exists?(project2.repository_storage_path, "#{old_path}.git")).to be(false)
- expect(gitlab_shell.exists?(project2.repository_storage_path, "#{new_path}.git")).to be(true)
+ expect(gitlab_shell.exists?(project2.repository_storage, "#{old_path}.git")).to be(false)
+ expect(gitlab_shell.exists?(project2.repository_storage, "#{new_path}.git")).to be(true)
end
it 'returns false when the command fails' do
- expect(gitlab_shell.mv_repository(project2.repository_storage_path, project2.disk_path, '')).to be_falsy
- expect(gitlab_shell.exists?(project2.repository_storage_path, "#{project2.disk_path}.git")).to be(true)
+ expect(gitlab_shell.mv_repository(project2.repository_storage, project2.disk_path, '')).to be_falsy
+ expect(gitlab_shell.exists?(project2.repository_storage, "#{project2.disk_path}.git")).to be(true)
end
end
@@ -679,55 +679,55 @@ describe Gitlab::Shell do
describe 'namespace actions' do
subject { described_class.new }
- let(:storage_path) { Gitlab.config.repositories.storages.default.legacy_disk_path }
+ let(:storage) { Gitlab.config.repositories.storages.keys.first }
describe '#add_namespace' do
it 'creates a namespace' do
- subject.add_namespace(storage_path, "mepmep")
+ subject.add_namespace(storage, "mepmep")
- expect(subject.exists?(storage_path, "mepmep")).to be(true)
+ expect(subject.exists?(storage, "mepmep")).to be(true)
end
end
describe '#exists?' do
context 'when the namespace does not exist' do
it 'returns false' do
- expect(subject.exists?(storage_path, "non-existing")).to be(false)
+ expect(subject.exists?(storage, "non-existing")).to be(false)
end
end
context 'when the namespace exists' do
it 'returns true' do
- subject.add_namespace(storage_path, "mepmep")
+ subject.add_namespace(storage, "mepmep")
- expect(subject.exists?(storage_path, "mepmep")).to be(true)
+ expect(subject.exists?(storage, "mepmep")).to be(true)
end
end
end
describe '#remove' do
it 'removes the namespace' do
- subject.add_namespace(storage_path, "mepmep")
- subject.rm_namespace(storage_path, "mepmep")
+ subject.add_namespace(storage, "mepmep")
+ subject.rm_namespace(storage, "mepmep")
- expect(subject.exists?(storage_path, "mepmep")).to be(false)
+ expect(subject.exists?(storage, "mepmep")).to be(false)
end
end
describe '#mv_namespace' do
it 'renames the namespace' do
- subject.add_namespace(storage_path, "mepmep")
- subject.mv_namespace(storage_path, "mepmep", "2mep")
+ subject.add_namespace(storage, "mepmep")
+ subject.mv_namespace(storage, "mepmep", "2mep")
- expect(subject.exists?(storage_path, "mepmep")).to be(false)
- expect(subject.exists?(storage_path, "2mep")).to be(true)
+ expect(subject.exists?(storage, "mepmep")).to be(false)
+ expect(subject.exists?(storage, "2mep")).to be(true)
end
end
end
def find_in_authorized_keys_file(key_id)
gitlab_shell.batch_read_key_ids do |ids|
- return true if ids.include?(key_id)
+ return true if ids.include?(key_id) # rubocop:disable Cop/AvoidReturnFromBlocks
end
false
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 40c8286b1b9..97b6069f64d 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -32,6 +32,12 @@ describe Gitlab::UserAccess do
let(:empty_project) { create(:project_empty_repo) }
let(:project_access) { described_class.new(user, project: empty_project) }
+ it 'returns true for admins' do
+ user.update!(admin: true)
+
+ expect(access.can_push_to_branch?('master')).to be_truthy
+ end
+
it 'returns true if user is master' do
empty_project.add_master(user)
@@ -71,6 +77,12 @@ describe Gitlab::UserAccess do
let(:branch) { create :protected_branch, project: project, name: "test" }
let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project }
+ it 'returns true for admins' do
+ user.update!(admin: true)
+
+ expect(access.can_push_to_branch?(branch.name)).to be_truthy
+ end
+
it 'returns true if user is a master' do
project.add_master(user)
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index 71a743495a2..4ba99009855 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
describe Gitlab::Utils do
- delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, :ensure_array_from_string, to: :described_class
+ delegate :to_boolean, :boolean_to_yes_no, :slugify, :random_string, :which, :ensure_array_from_string,
+ :bytes_to_megabytes, to: :described_class
describe '.slugify' do
{
@@ -97,4 +98,12 @@ describe Gitlab::Utils do
expect(ensure_array_from_string(str)).to eq(%w[seven eight 9 10])
end
end
+
+ describe '.bytes_to_megabytes' do
+ it 'converts bytes to megabytes' do
+ bytes = 1.megabyte
+
+ expect(bytes_to_megabytes(bytes)).to eq(1)
+ end
+ end
end
diff --git a/spec/lib/gitlab/view/presenter/base_spec.rb b/spec/lib/gitlab/view/presenter/base_spec.rb
index 32a946ca034..4eca53032a2 100644
--- a/spec/lib/gitlab/view/presenter/base_spec.rb
+++ b/spec/lib/gitlab/view/presenter/base_spec.rb
@@ -48,4 +48,11 @@ describe Gitlab::View::Presenter::Base do
end
end
end
+
+ describe '#present' do
+ it 'returns self' do
+ presenter = presenter_class.new(build_stubbed(:project))
+ expect(presenter.present).to eq(presenter)
+ end
+ end
end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 2b3ffb2d7c0..e732b089d44 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::Workhorse do
let(:ref) { 'master' }
let(:format) { 'zip' }
let(:storage_path) { Gitlab.config.gitlab.repository_downloads_path }
- let(:base_params) { repository.archive_metadata(ref, storage_path, format) }
+ let(:base_params) { repository.archive_metadata(ref, storage_path, format, append_sha: nil) }
let(:gitaly_params) do
base_params.merge(
'GitalyServer' => {
@@ -29,7 +29,7 @@ describe Gitlab::Workhorse do
let(:cache_disabled) { false }
subject do
- described_class.send_git_archive(repository, ref: ref, format: format)
+ described_class.send_git_archive(repository, ref: ref, format: format, append_sha: nil)
end
before do
@@ -482,4 +482,26 @@ describe Gitlab::Workhorse do
}.deep_stringify_keys)
end
end
+
+ describe '.send_git_snapshot' do
+ let(:url) { 'http://example.com' }
+
+ subject(:request) { described_class.send_git_snapshot(repository) }
+
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(request)
+
+ expect(key).to eq("Gitlab-Workhorse-Send-Data")
+ expect(command).to eq('git-snapshot')
+ expect(params).to eq(
+ 'GitalyServer' => {
+ 'address' => Gitlab::GitalyClient.address(project.repository_storage),
+ 'token' => Gitlab::GitalyClient.token(project.repository_storage)
+ },
+ 'GetSnapshotRequest' => Gitaly::GetSnapshotRequest.new(
+ repository: repository.gitaly_repository
+ ).to_json
+ )
+ end
+ end
end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
index f97136f0191..da146e24893 100644
--- a/spec/lib/gitlab_spec.rb
+++ b/spec/lib/gitlab_spec.rb
@@ -1,6 +1,14 @@
-require 'rails_helper'
+require 'fast_spec_helper'
+
+require_dependency 'gitlab'
describe Gitlab do
+ describe '.root' do
+ it 'returns the root path of the app' do
+ expect(described_class.root).to eq(Pathname.new(File.expand_path('../..', __dir__)))
+ end
+ end
+
describe '.com?' do
it 'is true when on GitLab.com' do
stub_config_setting(url: 'https://gitlab.com')
@@ -14,6 +22,12 @@ describe Gitlab do
expect(described_class.com?).to eq true
end
+ it 'is true when on other gitlab subdomain' do
+ stub_config_setting(url: 'https://example.gitlab.com')
+
+ expect(described_class.com?).to eq true
+ end
+
it 'is false when not on GitLab.com' do
stub_config_setting(url: 'http://example.com')
diff --git a/spec/lib/omni_auth/strategies/jwt_spec.rb b/spec/lib/omni_auth/strategies/jwt_spec.rb
new file mode 100644
index 00000000000..23485fbcb18
--- /dev/null
+++ b/spec/lib/omni_auth/strategies/jwt_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+describe OmniAuth::Strategies::Jwt do
+ include Rack::Test::Methods
+ include DeviseHelpers
+
+ context '.decoded' do
+ let(:strategy) { described_class.new({}) }
+ let(:timestamp) { Time.now.to_i }
+ let(:jwt_config) { Devise.omniauth_configs[:jwt] }
+ let(:key) { JWT.encode(claims, jwt_config.strategy.secret) }
+
+ let(:claims) do
+ {
+ id: 123,
+ name: "user_example",
+ email: "user@example.com",
+ iat: timestamp
+ }
+ end
+
+ before do
+ allow_any_instance_of(OmniAuth::Strategy).to receive(:options).and_return(jwt_config.strategy)
+ allow_any_instance_of(Rack::Request).to receive(:params).and_return({ 'jwt' => key })
+ end
+
+ it 'decodes the user information' do
+ result = strategy.decoded
+
+ expect(result["id"]).to eq(123)
+ expect(result["name"]).to eq("user_example")
+ expect(result["email"]).to eq("user@example.com")
+ expect(result["iat"]).to eq(timestamp)
+ end
+
+ context 'required claims is missing' do
+ let(:claims) do
+ {
+ id: 123,
+ email: "user@example.com",
+ iat: timestamp
+ }
+ end
+
+ it 'raises error' do
+ expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::JWT::ClaimInvalid)
+ end
+ end
+
+ context 'when valid_within is specified but iat attribute is missing in response' do
+ let(:claims) do
+ {
+ id: 123,
+ name: "user_example",
+ email: "user@example.com"
+ }
+ end
+
+ before do
+ jwt_config.strategy.valid_within = Time.now.to_i
+ end
+
+ it 'raises error' do
+ expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::JWT::ClaimInvalid)
+ end
+ end
+
+ context 'when timestamp claim is too skewed from present' do
+ let(:claims) do
+ {
+ id: 123,
+ name: "user_example",
+ email: "user@example.com",
+ iat: timestamp - 10.minutes.to_i
+ }
+ end
+
+ before do
+ jwt_config.strategy.valid_within = 2.seconds
+ end
+
+ it 'raises error' do
+ expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::JWT::ClaimInvalid)
+ end
+ end
+ end
+end
diff --git a/spec/lib/rspec_flaky/config_spec.rb b/spec/lib/rspec_flaky/config_spec.rb
index 83556787e85..4a71b1feebd 100644
--- a/spec/lib/rspec_flaky/config_spec.rb
+++ b/spec/lib/rspec_flaky/config_spec.rb
@@ -16,23 +16,25 @@ describe RspecFlaky::Config, :aggregate_failures do
end
end
- context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is set to 'false'" do
- before do
- stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'false')
- end
-
- it 'returns false' do
- expect(described_class).not_to be_generate_report
+ context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is set" do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:env_value, :result) do
+ '1' | true
+ 'true' | true
+ 'foo' | false
+ '0' | false
+ 'false' | false
end
- end
- context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is set to 'true'" do
- before do
- stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'true')
- end
+ with_them do
+ before do
+ stub_env('FLAKY_RSPEC_GENERATE_REPORT', env_value)
+ end
- it 'returns true' do
- expect(described_class).to be_generate_report
+ it 'returns false' do
+ expect(described_class.generate_report?).to be(result)
+ end
end
end
end
diff --git a/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb b/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb
index 06a8ba0d02e..6731a27ed17 100644
--- a/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb
+++ b/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb
@@ -24,14 +24,6 @@ describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures do
}
end
- describe '.from_json' do
- it 'accepts a JSON' do
- collection = described_class.from_json(JSON.pretty_generate(collection_hash))
-
- expect(collection.to_report).to eq(described_class.new(collection_hash).to_report)
- end
- end
-
describe '#initialize' do
it 'accepts no argument' do
expect { described_class.new }.not_to raise_error
@@ -46,11 +38,11 @@ describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures do
end
end
- describe '#to_report' do
+ describe '#to_h' do
it 'calls #to_h on the values' do
collection = described_class.new(collection_hash)
- expect(collection.to_report).to eq(collection_report)
+ expect(collection.to_h).to eq(collection_report)
end
end
@@ -61,7 +53,7 @@ describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures do
a: { example_id: 'spec/foo/bar_spec.rb:2' },
c: { example_id: 'spec/bar/baz_spec.rb:4' })
- expect((collection2 - collection1).to_report).to eq(
+ expect((collection2 - collection1).to_h).to eq(
c: {
example_id: 'spec/bar/baz_spec.rb:4',
first_flaky_at: nil,
diff --git a/spec/lib/rspec_flaky/listener_spec.rb b/spec/lib/rspec_flaky/listener_spec.rb
index bfb7648b486..ef085445081 100644
--- a/spec/lib/rspec_flaky/listener_spec.rb
+++ b/spec/lib/rspec_flaky/listener_spec.rb
@@ -4,7 +4,7 @@ describe RspecFlaky::Listener, :aggregate_failures do
let(:already_flaky_example_uid) { '6e869794f4cfd2badd93eb68719371d1' }
let(:suite_flaky_example_report) do
{
- already_flaky_example_uid => {
+ "#{already_flaky_example_uid}": {
example_id: 'spec/foo/bar_spec.rb:2',
file: 'spec/foo/bar_spec.rb',
line: 2,
@@ -55,8 +55,7 @@ describe RspecFlaky::Listener, :aggregate_failures do
it 'returns a valid Listener instance' do
listener = described_class.new
- expect(listener.to_report(listener.suite_flaky_examples))
- .to eq(expected_suite_flaky_examples)
+ expect(listener.suite_flaky_examples.to_h).to eq(expected_suite_flaky_examples)
expect(listener.flaky_examples).to eq({})
end
end
@@ -65,25 +64,35 @@ describe RspecFlaky::Listener, :aggregate_failures do
it_behaves_like 'a valid Listener instance'
end
- context 'when a report file exists and set by SUITE_FLAKY_RSPEC_REPORT_PATH' do
- let(:report_file) do
- Tempfile.new(%w[rspec_flaky_report .json]).tap do |f|
- f.write(JSON.pretty_generate(suite_flaky_example_report))
- f.rewind
- end
- end
+ context 'when SUITE_FLAKY_RSPEC_REPORT_PATH is set' do
+ let(:report_file_path) { 'foo/report.json' }
before do
- stub_env('SUITE_FLAKY_RSPEC_REPORT_PATH', report_file.path)
+ stub_env('SUITE_FLAKY_RSPEC_REPORT_PATH', report_file_path)
end
- after do
- report_file.close
- report_file.unlink
+ context 'and report file exists' do
+ before do
+ expect(File).to receive(:exist?).with(report_file_path).and_return(true)
+ end
+
+ it 'delegates the load to RspecFlaky::Report' do
+ report = RspecFlaky::Report.new(RspecFlaky::FlakyExamplesCollection.new(suite_flaky_example_report))
+
+ expect(RspecFlaky::Report).to receive(:load).with(report_file_path).and_return(report)
+ expect(described_class.new.suite_flaky_examples.to_h).to eq(report.flaky_examples.to_h)
+ end
end
- it_behaves_like 'a valid Listener instance' do
- let(:expected_suite_flaky_examples) { suite_flaky_example_report }
+ context 'and report file does not exist' do
+ before do
+ expect(File).to receive(:exist?).with(report_file_path).and_return(false)
+ end
+
+ it 'return an empty hash' do
+ expect(RspecFlaky::Report).not_to receive(:load)
+ expect(described_class.new.suite_flaky_examples.to_h).to eq({})
+ end
end
end
end
@@ -186,74 +195,21 @@ describe RspecFlaky::Listener, :aggregate_failures do
let(:notification_already_flaky_rspec_example) { double(example: already_flaky_rspec_example) }
context 'when a report file path is set by FLAKY_RSPEC_REPORT_PATH' do
- let(:report_file_path) { Rails.root.join('tmp', 'rspec_flaky_report.json') }
- let(:new_report_file_path) { Rails.root.join('tmp', 'rspec_flaky_new_report.json') }
+ it 'delegates the writes to RspecFlaky::Report' do
+ listener.example_passed(notification_new_flaky_rspec_example)
+ listener.example_passed(notification_already_flaky_rspec_example)
- before do
- stub_env('FLAKY_RSPEC_REPORT_PATH', report_file_path)
- stub_env('NEW_FLAKY_RSPEC_REPORT_PATH', new_report_file_path)
- FileUtils.rm(report_file_path) if File.exist?(report_file_path)
- FileUtils.rm(new_report_file_path) if File.exist?(new_report_file_path)
- end
+ report1 = double
+ report2 = double
- after do
- FileUtils.rm(report_file_path) if File.exist?(report_file_path)
- FileUtils.rm(new_report_file_path) if File.exist?(new_report_file_path)
- end
+ expect(RspecFlaky::Report).to receive(:new).with(listener.flaky_examples).and_return(report1)
+ expect(report1).to receive(:write).with(RspecFlaky::Config.flaky_examples_report_path)
- context 'when FLAKY_RSPEC_GENERATE_REPORT == "false"' do
- before do
- stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'false')
- end
-
- it 'does not write any report file' do
- listener.example_passed(notification_new_flaky_rspec_example)
+ expect(RspecFlaky::Report).to receive(:new).with(listener.flaky_examples - listener.suite_flaky_examples).and_return(report2)
+ expect(report2).to receive(:write).with(RspecFlaky::Config.new_flaky_examples_report_path)
- listener.dump_summary(nil)
-
- expect(File.exist?(report_file_path)).to be(false)
- expect(File.exist?(new_report_file_path)).to be(false)
- end
+ listener.dump_summary(nil)
end
-
- context 'when FLAKY_RSPEC_GENERATE_REPORT == "true"' do
- before do
- stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'true')
- end
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- it 'writes the report files' do
- listener.example_passed(notification_new_flaky_rspec_example)
- listener.example_passed(notification_already_flaky_rspec_example)
-
- listener.dump_summary(nil)
-
- expect(File.exist?(report_file_path)).to be(true)
- expect(File.exist?(new_report_file_path)).to be(true)
-
- expect(File.read(report_file_path))
- .to eq(JSON.pretty_generate(listener.to_report(listener.flaky_examples)))
-
- new_example = RspecFlaky::Example.new(notification_new_flaky_rspec_example)
- new_flaky_example = RspecFlaky::FlakyExample.new(new_example)
- new_flaky_example.update_flakiness!
-
- expect(File.read(new_report_file_path))
- .to eq(JSON.pretty_generate(listener.to_report(new_example.uid => new_flaky_example)))
- end
- end
- end
- end
-
- describe '#to_report' do
- let(:listener) { described_class.new(suite_flaky_example_report.to_json) }
-
- it 'transforms the internal hash to a JSON-ready hash' do
- expect(listener.to_report(already_flaky_example_uid => already_flaky_example))
- .to match(hash_including(suite_flaky_example_report))
end
end
end
diff --git a/spec/lib/rspec_flaky/report_spec.rb b/spec/lib/rspec_flaky/report_spec.rb
new file mode 100644
index 00000000000..7d57d99f7e5
--- /dev/null
+++ b/spec/lib/rspec_flaky/report_spec.rb
@@ -0,0 +1,125 @@
+require 'spec_helper'
+
+describe RspecFlaky::Report, :aggregate_failures do
+ let(:a_hundred_days) { 3600 * 24 * 100 }
+ let(:collection_hash) do
+ {
+ a: { example_id: 'spec/foo/bar_spec.rb:2' },
+ b: { example_id: 'spec/foo/baz_spec.rb:3', first_flaky_at: (Time.now - a_hundred_days).to_s, last_flaky_at: (Time.now - a_hundred_days).to_s }
+ }
+ end
+ let(:suite_flaky_example_report) do
+ {
+ '6e869794f4cfd2badd93eb68719371d1': {
+ example_id: 'spec/foo/bar_spec.rb:2',
+ file: 'spec/foo/bar_spec.rb',
+ line: 2,
+ description: 'hello world',
+ first_flaky_at: 1234,
+ last_flaky_at: 4321,
+ last_attempts_count: 3,
+ flaky_reports: 1,
+ last_flaky_job: nil
+ }
+ }
+ end
+ let(:flaky_examples) { RspecFlaky::FlakyExamplesCollection.new(collection_hash) }
+ let(:report) { described_class.new(flaky_examples) }
+
+ describe '.load' do
+ let!(:report_file) do
+ Tempfile.new(%w[rspec_flaky_report .json]).tap do |f|
+ f.write(JSON.pretty_generate(suite_flaky_example_report))
+ f.rewind
+ end
+ end
+
+ after do
+ report_file.close
+ report_file.unlink
+ end
+
+ it 'loads the report file' do
+ expect(described_class.load(report_file.path).flaky_examples.to_h).to eq(suite_flaky_example_report)
+ end
+ end
+
+ describe '.load_json' do
+ let(:report_json) do
+ JSON.pretty_generate(suite_flaky_example_report)
+ end
+
+ it 'loads the report file' do
+ expect(described_class.load_json(report_json).flaky_examples.to_h).to eq(suite_flaky_example_report)
+ end
+ end
+
+ describe '#initialize' do
+ it 'accepts a RspecFlaky::FlakyExamplesCollection' do
+ expect { report }.not_to raise_error
+ end
+
+ it 'does not accept anything else' do
+ expect { described_class.new([1, 2, 3]) }.to raise_error(ArgumentError, "`flaky_examples` must be a RspecFlaky::FlakyExamplesCollection, Array given!")
+ end
+ end
+
+ it 'delegates to #flaky_examples using SimpleDelegator' do
+ expect(report.__getobj__).to eq(flaky_examples)
+ end
+
+ describe '#write' do
+ let(:report_file_path) { Rails.root.join('tmp', 'rspec_flaky_report.json') }
+
+ before do
+ FileUtils.rm(report_file_path) if File.exist?(report_file_path)
+ end
+
+ after do
+ FileUtils.rm(report_file_path) if File.exist?(report_file_path)
+ end
+
+ context 'when RspecFlaky::Config.generate_report? is false' do
+ before do
+ allow(RspecFlaky::Config).to receive(:generate_report?).and_return(false)
+ end
+
+ it 'does not write any report file' do
+ report.write(report_file_path)
+
+ expect(File.exist?(report_file_path)).to be(false)
+ end
+ end
+
+ context 'when RspecFlaky::Config.generate_report? is true' do
+ before do
+ allow(RspecFlaky::Config).to receive(:generate_report?).and_return(true)
+ end
+
+ it 'delegates the writes to RspecFlaky::Report' do
+ report.write(report_file_path)
+
+ expect(File.exist?(report_file_path)).to be(true)
+ expect(File.read(report_file_path))
+ .to eq(JSON.pretty_generate(report.flaky_examples.to_h))
+ end
+ end
+ end
+
+ describe '#prune_outdated' do
+ it 'returns a new collection without the examples older than 90 days by default' do
+ new_report = flaky_examples.to_h.dup.tap { |r| r.delete(:b) }
+ new_flaky_examples = report.prune_outdated
+
+ expect(new_flaky_examples).to be_a(described_class)
+ expect(new_flaky_examples.to_h).to eq(new_report)
+ expect(flaky_examples).to have_key(:b)
+ end
+
+ it 'accepts a given number of days' do
+ new_flaky_examples = report.prune_outdated(days: 200)
+
+ expect(new_flaky_examples.to_h).to eq(report.to_h)
+ end
+ end
+end
diff --git a/spec/lib/uploaded_file_spec.rb b/spec/lib/uploaded_file_spec.rb
new file mode 100644
index 00000000000..cc99e7e8911
--- /dev/null
+++ b/spec/lib/uploaded_file_spec.rb
@@ -0,0 +1,116 @@
+require 'spec_helper'
+
+describe UploadedFile do
+ describe ".from_params" do
+ let(:temp_dir) { Dir.tmpdir }
+ let(:temp_file) { Tempfile.new("test", temp_dir) }
+ let(:upload_path) { nil }
+
+ subject do
+ described_class.from_params(params, :file, upload_path)
+ end
+
+ before do
+ FileUtils.touch(temp_file)
+ end
+
+ after do
+ FileUtils.rm_f(temp_file)
+ FileUtils.rm_r(upload_path) if upload_path
+ end
+
+ context 'when valid file is specified' do
+ context 'only local path is specified' do
+ let(:params) do
+ { 'file.path' => temp_file.path }
+ end
+
+ it "succeeds" do
+ is_expected.not_to be_nil
+ end
+
+ it "generates filename from path" do
+ expect(subject.original_filename).to eq(::File.basename(temp_file.path))
+ end
+ end
+
+ context 'all parameters are specified' do
+ let(:params) do
+ { 'file.path' => temp_file.path,
+ 'file.name' => 'my_file.txt',
+ 'file.type' => 'my/type',
+ 'file.sha256' => 'sha256',
+ 'file.remote_id' => 'remote_id' }
+ end
+
+ it "succeeds" do
+ is_expected.not_to be_nil
+ end
+
+ it "generates filename from path" do
+ expect(subject.original_filename).to eq('my_file.txt')
+ expect(subject.content_type).to eq('my/type')
+ expect(subject.sha256).to eq('sha256')
+ expect(subject.remote_id).to eq('remote_id')
+ end
+ end
+ end
+
+ context 'when no params are specified' do
+ let(:params) do
+ {}
+ end
+
+ it "does not return an object" do
+ is_expected.to be_nil
+ end
+ end
+
+ context 'when only remote id is specified' do
+ let(:params) do
+ { 'file.remote_id' => 'remote_id' }
+ end
+
+ it "raises an error" do
+ expect { subject }.to raise_error(UploadedFile::InvalidPathError, /file is invalid/)
+ end
+ end
+
+ context 'when verifying allowed paths' do
+ let(:params) do
+ { 'file.path' => temp_file.path }
+ end
+
+ context 'when file is stored in system temporary folder' do
+ let(:temp_dir) { Dir.tmpdir }
+
+ it "succeeds" do
+ is_expected.not_to be_nil
+ end
+ end
+
+ context 'when file is stored in user provided upload path' do
+ let(:upload_path) { Dir.mktmpdir }
+ let(:temp_dir) { upload_path }
+
+ it "succeeds" do
+ is_expected.not_to be_nil
+ end
+ end
+
+ context 'when file is stored outside of user provided upload path' do
+ let!(:generated_dir) { Dir.mktmpdir }
+ let!(:temp_dir) { Dir.mktmpdir }
+
+ before do
+ # We overwrite default temporary path
+ allow(Dir).to receive(:tmpdir).and_return(generated_dir)
+ end
+
+ it "raises an error" do
+ expect { subject }.to raise_error(UploadedFile::InvalidPathError, /insecure path used/)
+ end
+ end
+ end
+ end
+end