summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2017-09-06 21:00:47 +0200
committerKamil Trzcinski <ayufan@ayufan.eu>2017-09-06 21:00:47 +0200
commitcd8ea329f0d64c04e5dee00fb8916268dae7a6f7 (patch)
treea77f550a9acfce3c64484ff9f300a560b6587bd0 /spec
parent632f6ba267bc09a658defc3721d2b52de05cf7e6 (diff)
parentbb1ad6edcd62d8e8b8a1a37ed0782bdf7bf2bbd1 (diff)
downloadgitlab-ce-cd8ea329f0d64c04e5dee00fb8916268dae7a6f7.tar.gz
Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into zj/gitlab-ce-zj-auto-devops-table
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/profiles_controller_spec.rb25
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb8
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb22
-rw-r--r--spec/features/admin/admin_browses_logs_spec.rb8
-rw-r--r--spec/features/issues/form_spec.rb6
-rw-r--r--spec/features/merge_requests/diff_notes_avatars_spec.rb4
-rw-r--r--spec/features/merge_requests/form_spec.rb7
-rw-r--r--spec/features/projects/sub_group_issuables_spec.rb3
-rw-r--r--spec/helpers/blame_helper_spec.rb27
-rw-r--r--spec/helpers/groups_helper_spec.rb3
-rw-r--r--spec/helpers/markup_helper_spec.rb91
-rw-r--r--spec/helpers/notes_helper_spec.rb12
-rw-r--r--spec/helpers/profiles_helper_spec.rb31
-rw-r--r--spec/lib/banzai/commit_renderer_spec.rb19
-rw-r--r--spec/lib/banzai/filter/table_of_contents_filter_spec.rb36
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb90
-rw-r--r--spec/lib/banzai/renderer_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/path_spec.rb64
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb19
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb85
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb19
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb190
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb179
-rw-r--r--spec/models/concerns/issuable_spec.rb67
-rw-r--r--spec/models/user_spec.rb66
-rw-r--r--spec/requests/api/commits_spec.rb6
-rw-r--r--spec/requests/api/internal_spec.rb31
-rw-r--r--spec/requests/api/jobs_spec.rb94
-rw-r--r--spec/services/ci/retry_build_service_spec.rb11
-rw-r--r--spec/support/seed_helper.rb2
30 files changed, 1057 insertions, 204 deletions
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index 9d60dab12d1..b52b63e05a4 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -16,7 +16,11 @@ describe ProfilesController do
end
it "ignores an email update from a user with an external email address" do
- ldap_user = create(:omniauth_user, external_email: true)
+ stub_omniauth_setting(sync_profile_from_provider: ['ldap'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+
+ ldap_user = create(:omniauth_user)
+ ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true)
sign_in(ldap_user)
put :update,
@@ -27,5 +31,24 @@ describe ProfilesController do
expect(response.status).to eq(302)
expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com')
end
+
+ it "ignores an email and name update but allows a location update from a user with external email and name, but not external location" do
+ stub_omniauth_setting(sync_profile_from_provider: ['ldap'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+
+ ldap_user = create(:omniauth_user, name: 'Alex')
+ ldap_user.create_user_synced_attributes_metadata(provider: 'ldap', name_synced: true, email_synced: true, location_synced: false)
+ sign_in(ldap_user)
+
+ put :update,
+ user: { email: "john@gmail.com", name: "John", location: "City, Country" }
+
+ ldap_user.reload
+
+ expect(response.status).to eq(302)
+ expect(ldap_user.unconfirmed_email).not_to eq('john@gmail.com')
+ expect(ldap_user.name).not_to eq('John')
+ expect(ldap_user.location).to eq('City, Country')
+ end
end
end
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb
index d2c613a2423..caa63e7bd22 100644
--- a/spec/controllers/projects/artifacts_controller_spec.rb
+++ b/spec/controllers/projects/artifacts_controller_spec.rb
@@ -81,14 +81,6 @@ describe Projects::ArtifactsController do
expect(params['Entry']).to eq(Base64.encode64('ci_artifacts.txt'))
end
end
-
- context 'when the file does not exist' do
- it 'responds Not Found' do
- get :raw, namespace_id: project.namespace, project_id: project, job_id: job, path: 'unknown'
-
- expect(response).to be_not_found
- end
- end
end
describe 'GET latest_succeeded' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index bb67db268fa..6775012bab5 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -56,6 +56,28 @@ describe Projects::MergeRequestsController do
expect(response).to be_success
end
+
+ context "loads notes" do
+ let(:first_contributor) { create(:user) }
+ let(:contributor) { create(:user) }
+ let(:merge_request) { create(:merge_request, author: first_contributor, target_project: project, source_project: project) }
+ let(:contributor_merge_request) { create(:merge_request, :merged, author: contributor, target_project: project, source_project: project) }
+ # the order here is important
+ # as the controller reloads these from DB, references doesn't correspond after
+ let!(:first_contributor_note) { create(:note, author: first_contributor, noteable: merge_request, project: project) }
+ let!(:contributor_note) { create(:note, author: contributor, noteable: merge_request, project: project) }
+ let!(:owner_note) { create(:note, author: user, noteable: merge_request, project: project) }
+
+ it "with special_role FIRST_TIME_CONTRIBUTOR" do
+ go(format: :html)
+
+ notes = assigns(:notes)
+ expect(notes).to match(a_collection_containing_exactly(an_object_having_attributes(special_role: Note::SpecialRole::FIRST_TIME_CONTRIBUTOR),
+ an_object_having_attributes(special_role: nil),
+ an_object_having_attributes(special_role: nil)
+ ))
+ end
+ end
end
describe 'as json' do
diff --git a/spec/features/admin/admin_browses_logs_spec.rb b/spec/features/admin/admin_browses_logs_spec.rb
index 3e3404dfdac..02f50d7e27f 100644
--- a/spec/features/admin/admin_browses_logs_spec.rb
+++ b/spec/features/admin/admin_browses_logs_spec.rb
@@ -8,8 +8,10 @@ describe 'Admin browses logs' do
it 'shows available log files' do
visit admin_logs_path
- expect(page).to have_content 'test.log'
- expect(page).to have_content 'githost.log'
- expect(page).to have_content 'application.log'
+ expect(page).to have_link 'application.log'
+ expect(page).to have_link 'githost.log'
+ expect(page).to have_link 'test.log'
+ expect(page).to have_link 'sidekiq.log'
+ expect(page).to have_link 'repocheck.log'
end
end
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 4297bfff3d9..2db6f9a2982 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -166,12 +166,10 @@ describe 'New/edit issue', :js do
end
end
- page.within '.issuable-meta' do
+ page.within '.breadcrumbs' do
issue = Issue.find_by(title: 'title')
- expect(page).to have_text("Issue #{issue.to_reference}")
- # compare paths because the host differ in test
- expect(find_link(issue.to_reference)[:href]).to end_with(issue_path(issue))
+ expect(page).to have_text("Issues #{issue.to_reference}")
end
end
diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb
index e77f1f92731..ca536f2800c 100644
--- a/spec/features/merge_requests/diff_notes_avatars_spec.rb
+++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb
@@ -139,7 +139,7 @@ feature 'Diff note avatars', js: true do
end
page.within find("[id='#{position.line_code(project.repository)}']") do
- find('.diff-notes-collapse').click
+ find('.diff-notes-collapse').trigger('click')
expect(page).to have_selector('img.js-diff-comment-avatar', count: 2)
end
@@ -152,7 +152,7 @@ feature 'Diff note avatars', js: true do
page.within '.js-discussion-note-form' do
find('.js-note-text').native.send_keys('Test')
- find('.js-comment-button').trigger 'click'
+ find('.js-comment-button').trigger('click')
wait_for_requests
end
diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb
index 89410b0e90f..de98b147d04 100644
--- a/spec/features/merge_requests/form_spec.rb
+++ b/spec/features/merge_requests/form_spec.rb
@@ -84,13 +84,10 @@ describe 'New/edit merge request', :js do
end
end
- page.within '.issuable-meta' do
+ page.within '.breadcrumbs' do
merge_request = MergeRequest.find_by(source_branch: 'fix')
- expect(page).to have_text("Merge request #{merge_request.to_reference}")
- # compare paths because the host differ in test
- expect(find_link(merge_request.to_reference)[:href])
- .to end_with(merge_request_path(merge_request))
+ expect(page).to have_text("Merge Requests #{merge_request.to_reference}")
end
end
diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb
index b2b39dbd24c..eb2d3ff50a0 100644
--- a/spec/features/projects/sub_group_issuables_spec.rb
+++ b/spec/features/projects/sub_group_issuables_spec.rb
@@ -26,7 +26,6 @@ describe 'Subgroup Issuables', :js, :nested_groups do
def expect_to_have_full_subgroup_title
title = find('.breadcrumbs-links')
- expect(title).not_to have_selector '.initializing'
- expect(title).to have_content 'group / subgroup / project'
+ expect(title).to have_content 'group subgroup project'
end
end
diff --git a/spec/helpers/blame_helper_spec.rb b/spec/helpers/blame_helper_spec.rb
index b4368516d83..722d21c566f 100644
--- a/spec/helpers/blame_helper_spec.rb
+++ b/spec/helpers/blame_helper_spec.rb
@@ -35,25 +35,32 @@ describe BlameHelper do
end
describe '#age_map_class' do
- let(:dates) do
- [Time.zone.local(2014, 3, 17, 0, 0, 0)]
- end
- let(:blame_groups) do
- [
- { commit: double(committed_date: dates[0]) }
- ]
- end
+ let(:date) { Time.zone.local(2014, 3, 17, 0, 0, 0) }
+ let(:blame_groups) { [{ commit: double(committed_date: date) }] }
let(:duration) do
- project = double(created_at: dates[0])
+ project = double(created_at: date)
helper.age_map_duration(blame_groups, project)
end
it 'returns blame-commit-age-9 when oldest' do
- expect(helper.age_map_class(dates[0], duration)).to eq 'blame-commit-age-9'
+ expect(helper.age_map_class(date, duration)).to eq 'blame-commit-age-9'
end
it 'returns blame-commit-age-0 class when newest' do
expect(helper.age_map_class(duration[:now], duration)).to eq 'blame-commit-age-0'
end
+
+ context 'when called on the same day as project creation' do
+ let(:same_day_duration) do
+ project = double(created_at: now)
+ helper.age_map_duration(today_blame_groups, project)
+ end
+ let(:today_blame_groups) { [{ commit: double(committed_date: now) }] }
+ let(:now) { Time.zone.now }
+
+ it 'returns blame-commit-age-0 class' do
+ expect(helper.age_map_class(duration[:now], same_day_duration)).to eq 'blame-commit-age-0'
+ end
+ end
end
end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 9d6e03e3868..05f969904f5 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -91,7 +91,8 @@ describe GroupsHelper do
let!(:very_deep_nested_group) { create(:group, parent: deep_nested_group) }
it 'outputs the groups in the correct order' do
- expect(helper.group_title(very_deep_nested_group)).to match(/>#{group.name}<\/a>.*>#{nested_group.name}<\/a>.*>#{deep_nested_group.name}<\/a>/)
+ expect(helper.group_title(very_deep_nested_group))
+ .to match(/<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*<\/li>.*<a.*>#{very_deep_nested_group.name}<\/a>/m)
end
end
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 70eb01c9c44..03d706062b7 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -52,12 +52,71 @@ describe MarkupHelper do
end
end
- describe '#link_to_gfm' do
+ describe '#markdown_field' do
+ let(:attribute) { :title }
+
+ describe 'with already redacted attribute' do
+ it 'returns the redacted attribute' do
+ commit.redacted_title_html = 'commit title'
+
+ expect(Banzai).not_to receive(:render_field)
+
+ expect(helper.markdown_field(commit, attribute)).to eq('commit title')
+ end
+ end
+
+ describe 'without redacted attribute' do
+ it 'renders the markdown value' do
+ expect(Banzai).to receive(:render_field).with(commit, attribute).and_call_original
+
+ helper.markdown_field(commit, attribute)
+ end
+ end
+ end
+
+ describe '#link_to_markdown_field' do
+ let(:link) { '/commits/0a1b2c3d' }
+ let(:issues) { create_list(:issue, 2, project: project) }
+
+ it 'handles references nested in links with all the text' do
+ allow(commit).to receive(:title).and_return("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real")
+
+ actual = helper.link_to_markdown_field(commit, :title, link)
+ doc = Nokogiri::HTML.parse(actual)
+
+ # Make sure we didn't create invalid markup
+ expect(doc.errors).to be_empty
+
+ # Leading commit link
+ expect(doc.css('a')[0].attr('href')).to eq link
+ expect(doc.css('a')[0].text).to eq 'This should finally fix '
+
+ # First issue link
+ expect(doc.css('a')[1].attr('href'))
+ .to eq project_issue_path(project, issues[0])
+ expect(doc.css('a')[1].text).to eq issues[0].to_reference
+
+ # Internal commit link
+ expect(doc.css('a')[2].attr('href')).to eq link
+ expect(doc.css('a')[2].text).to eq ' and '
+
+ # Second issue link
+ expect(doc.css('a')[3].attr('href'))
+ .to eq project_issue_path(project, issues[1])
+ expect(doc.css('a')[3].text).to eq issues[1].to_reference
+
+ # Trailing commit link
+ expect(doc.css('a')[4].attr('href')).to eq link
+ expect(doc.css('a')[4].text).to eq ' for real'
+ end
+ end
+
+ describe '#link_to_markdown' do
let(:link) { '/commits/0a1b2c3d' }
let(:issues) { create_list(:issue, 2, project: project) }
it 'handles references nested in links with all the text' do
- actual = helper.link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", link)
+ actual = helper.link_to_markdown("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", link)
doc = Nokogiri::HTML.parse(actual)
# Make sure we didn't create invalid markup
@@ -87,7 +146,7 @@ describe MarkupHelper do
end
it 'forwards HTML options' do
- actual = helper.link_to_gfm("Fixed in #{commit.id}", link, class: 'foo')
+ actual = helper.link_to_markdown("Fixed in #{commit.id}", link, class: 'foo')
doc = Nokogiri::HTML.parse(actual)
expect(doc.css('a')).to satisfy do |v|
@@ -98,23 +157,43 @@ describe MarkupHelper do
it "escapes HTML passed in as the body" do
actual = "This is a <h1>test</h1> - see #{issues[0].to_reference}"
- expect(helper.link_to_gfm(actual, link))
+ expect(helper.link_to_markdown(actual, link))
.to match('&lt;h1&gt;test&lt;/h1&gt;')
end
it 'ignores reference links when they are the entire body' do
text = issues[0].to_reference
- act = helper.link_to_gfm(text, '/foo')
+ act = helper.link_to_markdown(text, '/foo')
expect(act).to eq %Q(<a href="/foo">#{issues[0].to_reference}</a>)
end
it 'replaces commit message with emoji to link' do
- actual = link_to_gfm(':book: Book', '/foo')
+ actual = link_to_markdown(':book: Book', '/foo')
expect(actual)
.to eq '<gl-emoji title="open book" data-name="book" data-unicode-version="6.0">📖</gl-emoji><a href="/foo"> Book</a>'
end
end
+ describe '#link_to_html' do
+ it 'wraps the rendered content in a link' do
+ link = '/commits/0a1b2c3d'
+ issue = create(:issue, project: project)
+
+ rendered = helper.markdown("This should finally fix #{issue.to_reference} for real", pipeline: :single_line)
+ doc = Nokogiri::HTML.parse(rendered)
+
+ expect(doc.css('a')[0].attr('href'))
+ .to eq project_issue_path(project, issue)
+ expect(doc.css('a')[0].text).to eq issue.to_reference
+
+ wrapped = helper.link_to_html(rendered, link)
+ doc = Nokogiri::HTML.parse(wrapped)
+
+ expect(doc.css('a')[0].attr('href')).to eq link
+ expect(doc.css('a')[0].text).to eq 'This should finally fix '
+ end
+ end
+
describe '#render_wiki_content' do
before do
@wiki = double('WikiPage')
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 68540dd4e59..cd15e27b497 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -23,10 +23,10 @@ describe NotesHelper do
end
describe "#notes_max_access_for_users" do
- it 'returns human access levels' do
- expect(helper.note_max_access_for_user(owner_note)).to eq('Owner')
- expect(helper.note_max_access_for_user(master_note)).to eq('Master')
- expect(helper.note_max_access_for_user(reporter_note)).to eq('Reporter')
+ it 'returns access levels' do
+ expect(helper.note_max_access_for_user(owner_note)).to eq(Gitlab::Access::OWNER)
+ expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER)
+ expect(helper.note_max_access_for_user(reporter_note)).to eq(Gitlab::Access::REPORTER)
end
it 'handles access in different projects' do
@@ -34,8 +34,8 @@ describe NotesHelper do
second_project.team << [master, :reporter]
other_note = create(:note, author: master, project: second_project)
- expect(helper.note_max_access_for_user(master_note)).to eq('Master')
- expect(helper.note_max_access_for_user(other_note)).to eq('Reporter')
+ expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER)
+ expect(helper.note_max_access_for_user(other_note)).to eq(Gitlab::Access::REPORTER)
end
end
diff --git a/spec/helpers/profiles_helper_spec.rb b/spec/helpers/profiles_helper_spec.rb
index b33b3f3a228..c1d0614c79e 100644
--- a/spec/helpers/profiles_helper_spec.rb
+++ b/spec/helpers/profiles_helper_spec.rb
@@ -6,22 +6,41 @@ describe ProfilesHelper do
user = create(:user)
allow(helper).to receive(:current_user).and_return(user)
- expect(helper.email_provider_label).to be_nil
+ expect(helper.attribute_provider_label(:email)).to be_nil
end
- it "returns omniauth provider label for users with external email" do
+ it "returns omniauth provider label for users with external attributes" do
+ stub_omniauth_setting(sync_profile_from_provider: ['cas3'])
+ stub_omniauth_setting(sync_profile_attributes: true)
stub_cas_omniauth_provider
- cas_user = create(:omniauth_user, provider: 'cas3', external_email: true, email_provider: 'cas3')
+ cas_user = create(:omniauth_user, provider: 'cas3')
+ cas_user.create_user_synced_attributes_metadata(provider: 'cas3', name_synced: true, email_synced: true, location_synced: true)
allow(helper).to receive(:current_user).and_return(cas_user)
- expect(helper.email_provider_label).to eq('CAS')
+ expect(helper.attribute_provider_label(:email)).to eq('CAS')
+ expect(helper.attribute_provider_label(:name)).to eq('CAS')
+ expect(helper.attribute_provider_label(:location)).to eq('CAS')
+ end
+
+ it "returns the correct omniauth provider label for users with some external attributes" do
+ stub_omniauth_setting(sync_profile_from_provider: ['cas3'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ stub_cas_omniauth_provider
+ cas_user = create(:omniauth_user, provider: 'cas3')
+ cas_user.create_user_synced_attributes_metadata(provider: 'cas3', name_synced: false, email_synced: true, location_synced: false)
+ allow(helper).to receive(:current_user).and_return(cas_user)
+
+ expect(helper.attribute_provider_label(:name)).to be_nil
+ expect(helper.attribute_provider_label(:email)).to eq('CAS')
+ expect(helper.attribute_provider_label(:location)).to be_nil
end
it "returns 'LDAP' for users with external email but no email provider" do
- ldap_user = create(:omniauth_user, external_email: true)
+ ldap_user = create(:omniauth_user)
+ ldap_user.create_user_synced_attributes_metadata(email_synced: true)
allow(helper).to receive(:current_user).and_return(ldap_user)
- expect(helper.email_provider_label).to eq('LDAP')
+ expect(helper.attribute_provider_label(:email)).to eq('LDAP')
end
end
diff --git a/spec/lib/banzai/commit_renderer_spec.rb b/spec/lib/banzai/commit_renderer_spec.rb
new file mode 100644
index 00000000000..049d025a5b9
--- /dev/null
+++ b/spec/lib/banzai/commit_renderer_spec.rb
@@ -0,0 +1,19 @@
+require 'spec_helper'
+
+describe Banzai::CommitRenderer do
+ describe '.render' do
+ it 'renders a commit description and title' do
+ user = double(:user)
+ project = create(:project, :repository)
+
+ expect(Banzai::ObjectRenderer).to receive(:new).with(project, user).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
+ expect(Banzai::Renderer).to receive(:cacheless_render_field).with(project.commit, attr)
+ end
+
+ described_class.render([project.commit], project, user)
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
index ff6b19459bb..85eddde732e 100644
--- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
+++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb
@@ -96,5 +96,41 @@ describe Banzai::Filter::TableOfContentsFilter do
expect(links.last.attr('href')).to eq '#header-2'
expect(links.last.text).to eq 'Header 2'
end
+
+ context 'table of contents nesting' do
+ let(:results) do
+ result(
+ header(1, 'Header 1') <<
+ header(2, 'Header 1-1') <<
+ header(3, 'Header 1-1-1') <<
+ header(2, 'Header 1-2') <<
+ header(1, 'Header 2') <<
+ header(2, 'Header 2-1')
+ )
+ end
+
+ it 'keeps list levels regarding header levels' do
+ items = doc.css('li')
+
+ # Header 1
+ expect(items[0].ancestors).to satisfy_none { |node| node.name == 'li' }
+
+ # Header 1-1
+ expect(items[1].ancestors).to include(items[0])
+
+ # Header 1-1-1
+ expect(items[2].ancestors).to include(items[0], items[1])
+
+ # Header 1-2
+ expect(items[3].ancestors).to include(items[0])
+ expect(items[3].ancestors).not_to include(items[1])
+
+ # Header 2
+ expect(items[4].ancestors).to satisfy_none { |node| node.name == 'li' }
+
+ # Header 2-1
+ expect(items[5].ancestors).to include(items[4])
+ end
+ end
end
end
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index 7f5d481c36c..b172a1b718c 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -1,53 +1,77 @@
require 'spec_helper'
describe Banzai::ObjectRenderer do
- let(:project) { create(:project) }
+ 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) }
describe '#render' do
- it 'renders and redacts an Array of objects' do
- renderer.render([object], :note)
+ context 'with cache' do
+ it 'renders and redacts an Array of objects' do
+ renderer.render([object], :note)
- expect(object.redacted_note_html).to eq '<p dir="auto">hello</p>'
- expect(object.user_visible_reference_count).to eq 0
- end
+ expect(object.redacted_note_html).to eq '<p dir="auto">hello</p>'
+ expect(object.user_visible_reference_count).to eq 0
+ end
- it 'calls Banzai::Redactor to perform redaction' do
- expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
+ it 'calls Banzai::Redactor to perform redaction' do
+ expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
- renderer.render([object], :note)
- end
+ renderer.render([object], :note)
+ end
- it 'retrieves field content using Banzai.render_field' do
- expect(Banzai).to receive(:render_field).with(object, :note).and_call_original
+ it 'retrieves field content using Banzai::Renderer.render_field' do
+ expect(Banzai::Renderer).to receive(:render_field).with(object, :note).and_call_original
- renderer.render([object], :note)
- end
+ renderer.render([object], :note)
+ end
- it 'passes context to PostProcessPipeline' do
- another_user = create(:user)
- another_project = create(:project)
- object = Note.new(
- note: 'hello',
- note_html: 'hello',
- author: another_user,
- project: another_project
- )
-
- expect(Banzai::Pipeline::PostProcessPipeline).to receive(:to_document).with(
- anything,
- hash_including(
- skip_redaction: true,
- current_user: user,
- project: another_project,
+ it 'passes context to PostProcessPipeline' do
+ another_user = create(:user)
+ another_project = create(:project)
+ object = Note.new(
+ note: 'hello',
+ note_html: 'hello',
author: another_user,
- custom_value: 'value'
+ project: another_project
)
- ).and_call_original
- renderer.render([object], :note)
+ expect(Banzai::Pipeline::PostProcessPipeline).to receive(:to_document).with(
+ anything,
+ hash_including(
+ skip_redaction: true,
+ current_user: user,
+ project: another_project,
+ author: another_user,
+ custom_value: 'value'
+ )
+ ).and_call_original
+
+ renderer.render([object], :note)
+ end
+ end
+
+ context 'without cache' do
+ let(:commit) { project.commit }
+
+ it 'renders and redacts an Array of objects' do
+ renderer.render([commit], :title)
+
+ expect(commit.redacted_title_html).to eq("Merge branch 'branch-merged' into 'master'")
+ end
+
+ it 'calls Banzai::Redactor to perform redaction' do
+ expect_any_instance_of(Banzai::Redactor).to receive(:redact).and_call_original
+
+ renderer.render([commit], :title)
+ end
+
+ it 'retrieves field content using Banzai::Renderer.cacheless_render_field' do
+ expect(Banzai::Renderer).to receive(:cacheless_render_field).with(commit, :title).and_call_original
+
+ renderer.render([commit], :title)
+ end
end
end
end
diff --git a/spec/lib/banzai/renderer_spec.rb b/spec/lib/banzai/renderer_spec.rb
index 0e094405e33..da42272bbef 100644
--- a/spec/lib/banzai/renderer_spec.rb
+++ b/spec/lib/banzai/renderer_spec.rb
@@ -4,6 +4,7 @@ describe Banzai::Renderer do
def fake_object(fresh:)
object = double('object')
+ allow(object).to receive(:respond_to?).with(:cached_markdown_fields).and_return(true)
allow(object).to receive(:cached_html_up_to_date?).with(:field).and_return(fresh)
allow(object).to receive(:cached_html_for).with(:field).and_return('field_html')
@@ -12,25 +13,38 @@ describe Banzai::Renderer do
describe '#render_field' do
let(:renderer) { described_class }
- subject { renderer.render_field(object, :field) }
- context 'with a stale cache' do
- let(:object) { fake_object(fresh: false) }
+ context 'without cache' do
+ let(:commit) { create(:project, :repository).commit }
- it 'caches and returns the result' do
- expect(object).to receive(:refresh_markdown_cache!).with(do_update: true)
+ it 'returns cacheless render field' do
+ expect(renderer).to receive(:cacheless_render_field).with(commit, :title)
- is_expected.to eq('field_html')
+ renderer.render_field(commit, :title)
end
end
- context 'with an up-to-date cache' do
- let(:object) { fake_object(fresh: true) }
+ context 'with cache' do
+ subject { renderer.render_field(object, :field) }
- it 'uses the cache' do
- expect(object).to receive(:refresh_markdown_cache!).never
+ context 'with a stale cache' do
+ let(:object) { fake_object(fresh: false) }
- is_expected.to eq('field_html')
+ it 'caches and returns the result' do
+ expect(object).to receive(:refresh_markdown_cache!).with(do_update: true)
+
+ is_expected.to eq('field_html')
+ end
+ end
+
+ context 'with an up-to-date cache' do
+ let(:object) { fake_object(fresh: true) }
+
+ it 'uses the cache' do
+ expect(object).to receive(:refresh_markdown_cache!).never
+
+ is_expected.to eq('field_html')
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/path_spec.rb b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
new file mode 100644
index 00000000000..7bd6a2ead25
--- /dev/null
+++ b/spec/lib/gitlab/ci/build/artifacts/path_spec.rb
@@ -0,0 +1,64 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Build::Artifacts::Path do
+ describe '#valid?' do
+ context 'when path contains a zero character' do
+ it 'is not valid' do
+ expect(described_class.new("something/\255")).not_to be_valid
+ end
+ end
+
+ context 'when path is not utf8 string' do
+ it 'is not valid' do
+ expect(described_class.new("something/\0")).not_to be_valid
+ end
+ end
+
+ context 'when path is valid' do
+ it 'is valid' do
+ expect(described_class.new("some/file/path")).to be_valid
+ end
+ end
+ end
+
+ describe '#directory?' do
+ context 'when path ends with a directory indicator' do
+ it 'is a directory' do
+ expect(described_class.new("some/file/dir/")).to be_directory
+ end
+ end
+
+ context 'when path does not end with a directory indicator' do
+ it 'is not a directory' do
+ expect(described_class.new("some/file")).not_to be_directory
+ end
+ end
+ end
+
+ describe '#name' do
+ it 'returns a base name' do
+ expect(described_class.new("some/file").name).to eq 'file'
+ end
+ end
+
+ describe '#nodes' do
+ it 'returns number of path nodes' do
+ expect(described_class.new("some/dir/file").nodes).to eq 2
+ end
+ end
+
+ describe '#to_s' do
+ context 'when path is valid' do
+ it 'returns a string representation of a path' do
+ expect(described_class.new('some/path').to_s).to eq 'some/path'
+ end
+ end
+
+ context 'when path is invalid' do
+ it 'raises an error' do
+ expect { described_class.new("invalid/\0").to_s }
+ .to raise_error ArgumentError
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index dfbdbee48f7..d39b33a0c05 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -273,6 +273,25 @@ EOT
end
end
+ describe '#json_safe_diff' do
+ let(:project) { create(:project, :repository) }
+
+ it 'fake binary message when it detects binary' do
+ # Rugged will not detect this as binary, but we can fake it
+ diff_message = "Binary files files/images/icn-time-tracking.pdf and files/images/icn-time-tracking.pdf differ\n"
+ binary_diff = described_class.between(project.repository, 'add-pdf-text-binary', 'add-pdf-text-binary^').first
+
+ expect(binary_diff.diff).not_to be_empty
+ expect(binary_diff.json_safe_diff).to eq(diff_message)
+ end
+
+ it 'leave non-binary diffs as-is' do
+ diff = described_class.new(@rugged_diff)
+
+ expect(diff.json_safe_diff).to eq(diff.diff)
+ end
+ end
+
describe '#submodule?' do
before do
commit = repository.lookup('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 08959e7bc16..556a148c3bc 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -390,46 +390,73 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe "#delete_branch" do
- before(:all) do
- @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
- @repo.delete_branch("feature")
+ shared_examples "deleting a branch" do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
+
+ after do
+ FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
+ ensure_seeds
+ end
+
+ it "removes the branch from the repo" do
+ branch_name = "to-be-deleted-soon"
+
+ repository.create_branch(branch_name)
+ expect(repository.rugged.branches[branch_name]).not_to be_nil
+
+ repository.delete_branch(branch_name)
+ expect(repository.rugged.branches[branch_name]).to be_nil
+ end
+
+ context "when branch does not exist" do
+ it "raises a DeleteBranchError exception" do
+ expect { repository.delete_branch("this-branch-does-not-exist") }.to raise_error(Gitlab::Git::Repository::DeleteBranchError)
+ end
+ end
end
- it "should remove the branch from the repo" do
- expect(@repo.rugged.branches["feature"]).to be_nil
+ context "when Gitaly delete_branch is enabled" do
+ it_behaves_like "deleting a branch"
end
- after(:all) do
- FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
- ensure_seeds
+ context "when Gitaly delete_branch is disabled", skip_gitaly_mock: true do
+ it_behaves_like "deleting a branch"
end
end
describe "#create_branch" do
- before(:all) do
- @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
- end
+ shared_examples 'creating a branch' do
+ let(:repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
- it "should create a new branch" do
- expect(@repo.create_branch('new_branch', 'master')).not_to be_nil
- end
+ after do
+ FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
+ ensure_seeds
+ end
- it "should create a new branch with the right name" do
- expect(@repo.create_branch('another_branch', 'master').name).to eq('another_branch')
- end
+ it "should create a new branch" do
+ expect(repository.create_branch('new_branch', 'master')).not_to be_nil
+ end
- it "should fail if we create an existing branch" do
- @repo.create_branch('duplicated_branch', 'master')
- expect {@repo.create_branch('duplicated_branch', 'master')}.to raise_error("Branch duplicated_branch already exists")
+ it "should create a new branch with the right name" do
+ expect(repository.create_branch('another_branch', 'master').name).to eq('another_branch')
+ end
+
+ it "should fail if we create an existing branch" do
+ repository.create_branch('duplicated_branch', 'master')
+ expect {repository.create_branch('duplicated_branch', 'master')}.to raise_error("Branch duplicated_branch already exists")
+ end
+
+ it "should fail if we create a branch from a non existing ref" do
+ expect {repository.create_branch('branch_based_in_wrong_ref', 'master_2_the_revenge')}.to raise_error("Invalid reference master_2_the_revenge")
+ end
end
- it "should fail if we create a branch from a non existing ref" do
- expect {@repo.create_branch('branch_based_in_wrong_ref', 'master_2_the_revenge')}.to raise_error("Invalid reference master_2_the_revenge")
+ context 'when Gitaly create_branch feature is enabled' do
+ it_behaves_like 'creating a branch'
end
- after(:all) do
- FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
- ensure_seeds
+ context 'when Gitaly create_branch feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'creating a branch'
end
end
@@ -905,7 +932,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'should set the autocrlf option to the provided option' do
@repo.autocrlf = :input
- File.open(File.join(SEED_STORAGE_PATH, TEST_MUTABLE_REPO_PATH, '.git', 'config')) do |config_file|
+ File.open(File.join(SEED_STORAGE_PATH, TEST_MUTABLE_REPO_PATH, 'config')) do |config_file|
expect(config_file.read).to match('autocrlf = input')
end
end
@@ -977,7 +1004,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'with local and remote branches' do
let(:repository) do
- Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'), '')
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
before do
@@ -1024,7 +1051,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'with local and remote branches' do
let(:repository) do
- Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'), '')
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
before do
@@ -1230,7 +1257,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#local_branches' do
before(:all) do
- @repo = Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'), '')
+ @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
after(:all) do
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 5100a5a609e..6a6e465cea2 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -37,7 +37,8 @@ describe Gitlab::LDAP::User do
end
it "does not mark existing ldap user as changed" do
- create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain', external_email: true, email_provider: 'ldapmain')
+ create(:omniauth_user, email: 'john@example.com', extern_uid: 'my-uid', provider: 'ldapmain')
+ ldap_user.gl_user.user_synced_attributes_metadata(provider: 'ldapmain', email: true)
expect(ldap_user.changed?).to be_falsey
end
end
@@ -141,12 +142,12 @@ describe Gitlab::LDAP::User do
expect(ldap_user.gl_user.email).to eq(info[:email])
end
- it "has external_email set to true" do
- expect(ldap_user.gl_user.external_email?).to be(true)
+ it "has user_synced_attributes_metadata email set to true" do
+ expect(ldap_user.gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
end
- it "has email_provider set to provider" do
- expect(ldap_user.gl_user.email_provider).to eql 'ldapmain'
+ it "has synced_attribute_provider set to ldapmain" do
+ expect(ldap_user.gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
end
end
@@ -156,11 +157,11 @@ describe Gitlab::LDAP::User do
end
it "has a temp email" do
- expect(ldap_user.gl_user.temp_oauth_email?).to be(true)
+ expect(ldap_user.gl_user.temp_oauth_email?).to be_truthy
end
- it "has external_email set to false" do
- expect(ldap_user.gl_user.external_email?).to be(false)
+ it "has synced attribute email set to false" do
+ expect(ldap_user.gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
end
end
end
@@ -168,7 +169,7 @@ describe Gitlab::LDAP::User do
describe 'blocking' do
def configure_block(value)
allow_any_instance_of(Gitlab::LDAP::Config)
- .to receive(:block_auto_created_users).and_return(value)
+ .to receive(:block_auto_created_users).and_return(value)
end
context 'signup' do
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 2cf0f7516de..8aaf320cbf5 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -10,7 +10,11 @@ describe Gitlab::OAuth::User do
{
nickname: '-john+gitlab-ETC%.git@gmail.com',
name: 'John',
- email: 'john@mail.com'
+ email: 'john@mail.com',
+ address: {
+ locality: 'locality',
+ country: 'country'
+ }
}
end
let(:ldap_user) { Gitlab::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
@@ -422,11 +426,12 @@ describe Gitlab::OAuth::User do
end
end
- describe 'updating email' do
+ describe 'ensure backwards compatibility with with sync email from provider option' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
before do
stub_omniauth_config(sync_email_from_provider: 'my-provider')
+ stub_omniauth_config(sync_profile_from_provider: ['my-provider'])
end
context "when provider sets an email" do
@@ -434,12 +439,12 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).to eq(info_hash[:email])
end
- it "has external_email set to true" do
- expect(gl_user.external_email?).to be(true)
+ it "has external_attributes set to true" do
+ expect(gl_user.user_synced_attributes_metadata).not_to be_nil
end
- it "has email_provider set to provider" do
- expect(gl_user.email_provider).to eql 'my-provider'
+ it "has attributes_provider set to my-provider" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
end
end
@@ -452,8 +457,9 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).not_to eq(info_hash[:email])
end
- it "has external_email set to false" do
- expect(gl_user.external_email?).to be(false)
+ it "has user_synced_attributes_metadata set to nil" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
end
end
end
@@ -487,4 +493,172 @@ describe Gitlab::OAuth::User do
end
end
end
+
+ describe 'updating email with sync profile' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_config(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_config(sync_profile_attributes: true)
+ end
+
+ context "when provider sets an email" do
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ end
+
+ it "has email_synced_attribute set to true" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
+ end
+
+ it "has my-provider as attributes_provider" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
+ end
+ end
+
+ context "when provider doesn't set an email" do
+ before do
+ info_hash.delete(:email)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.email).not_to eq(info_hash[:email])
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(false)
+ end
+ end
+ end
+
+ describe 'updating name' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ end
+
+ context "when provider sets a name" do
+ it "updates the user name" do
+ expect(gl_user.name).to eq(info_hash[:name])
+ end
+ end
+
+ context "when provider doesn't set a name" do
+ before do
+ info_hash.delete(:name)
+ end
+
+ it "does not update the user name" do
+ expect(gl_user.name).not_to eq(info_hash[:name])
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be(false)
+ end
+ end
+ end
+
+ describe 'updating location' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ end
+
+ context "when provider sets a location" do
+ it "updates the user location" do
+ expect(gl_user.location).to eq(info_hash[:address][:locality] + ', ' + info_hash[:address][:country])
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(true)
+ end
+ end
+
+ context "when provider doesn't set a location" do
+ before do
+ info_hash[:address].delete(:country)
+ info_hash[:address].delete(:locality)
+ end
+
+ it "does not update the user location" do
+ expect(gl_user.location).to be_nil
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(false)
+ end
+ end
+ end
+
+ describe 'updating user info' do
+ let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
+
+ context "update all info" do
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: true)
+ end
+
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
+ end
+
+ it "updates the user name" do
+ expect(gl_user.name).to eq(info_hash[:name])
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be(true)
+ end
+
+ it "updates the user location" do
+ expect(gl_user.location).to eq(info_hash[:address][:locality] + ', ' + info_hash[:address][:country])
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(true)
+ end
+
+ it "sets my-provider as the attributes provider" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql('my-provider')
+ end
+ end
+
+ context "update only requested info" do
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ stub_omniauth_setting(sync_profile_attributes: %w(name location))
+ end
+
+ it "updates the user name" do
+ expect(gl_user.name).to eq(info_hash[:name])
+ expect(gl_user.user_synced_attributes_metadata.name_synced).to be(true)
+ end
+
+ it "updates the user location" do
+ expect(gl_user.location).to eq(info_hash[:address][:locality] + ', ' + info_hash[:address][:country])
+ expect(gl_user.user_synced_attributes_metadata.location_synced).to be(true)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(false)
+ end
+ end
+
+ context "update default_scope" do
+ before do
+ stub_omniauth_setting(sync_profile_from_provider: ['my-provider'])
+ end
+
+ it "updates the user email" do
+ expect(gl_user.email).to eq(info_hash[:email])
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
+ end
+ end
+
+ context "update no info when profile sync is nil" do
+ it "does not have sync_attribute" do
+ expect(gl_user.user_synced_attributes_metadata).to be(nil)
+ end
+
+ it "does not update the user email" do
+ expect(gl_user.email).not_to eq(info_hash[:email])
+ end
+
+ it "does not update the user name" do
+ expect(gl_user.name).not_to eq(info_hash[:name])
+ end
+
+ it "does not update the user location" do
+ expect(gl_user.location).not_to eq(info_hash[:address][:country])
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
index 308b1a128be..fdc3990132a 100644
--- a/spec/lib/gitlab/url_sanitizer_spec.rb
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -1,11 +1,7 @@
require 'spec_helper'
describe Gitlab::UrlSanitizer do
- let(:credentials) { { user: 'blah', password: 'password' } }
- let(:url_sanitizer) do
- described_class.new("https://github.com/me/project.git", credentials: credentials)
- end
- let(:user) { double(:user, username: 'john.doe') }
+ using RSpec::Parameterized::TableSyntax
describe '.sanitize' do
def sanitize_url(url)
@@ -16,83 +12,166 @@ describe Gitlab::UrlSanitizer do
})
end
- it 'mask the credentials from HTTP URLs' do
- filtered_content = sanitize_url('http://user:pass@test.com/root/repoC.git/')
+ where(:input, :output) do
+ 'http://user:pass@test.com/root/repoC.git/' | 'http://*****:*****@test.com/root/repoC.git/'
+ 'https://user:pass@test.com/root/repoA.git/' | 'https://*****:*****@test.com/root/repoA.git/'
+ 'ssh://user@host.test/path/to/repo.git' | 'ssh://*****@host.test/path/to/repo.git'
- expect(filtered_content).to include("http://*****:*****@test.com/root/repoC.git/")
- end
+ # git protocol does not support authentication but clean any details anyway
+ 'git://user:pass@host.test/path/to/repo.git' | 'git://*****:*****@host.test/path/to/repo.git'
+ 'git://host.test/path/to/repo.git' | 'git://host.test/path/to/repo.git'
- it 'mask the credentials from HTTPS URLs' do
- filtered_content = sanitize_url('https://user:pass@test.com/root/repoA.git/')
+ # SCP-style URLs are left unmodified
+ 'user@server:project.git' | 'user@server:project.git'
+ 'user:pass@server:project.git' | 'user:pass@server:project.git'
- expect(filtered_content).to include("https://*****:*****@test.com/root/repoA.git/")
+ # return an empty string for invalid URLs
+ 'ssh://' | ''
end
- it 'mask credentials from SSH URLs' do
- filtered_content = sanitize_url('ssh://user@host.test/path/to/repo.git')
-
- expect(filtered_content).to include("ssh://*****@host.test/path/to/repo.git")
+ with_them do
+ it { expect(sanitize_url(input)).to include("repository '#{output}' not found") }
end
+ end
- it 'does not modify Git URLs' do
- # git protocol does not support authentication
- filtered_content = sanitize_url('git://host.test/path/to/repo.git')
+ describe '.valid?' do
+ where(:value, :url) do
+ false | nil
+ false | ''
+ false | '123://invalid:url'
+ true | 'valid@project:url.git'
+ true | 'ssh://example.com'
+ true | 'ssh://:@example.com'
+ true | 'ssh://foo@example.com'
+ true | 'ssh://foo:bar@example.com'
+ true | 'ssh://foo:bar@example.com/group/group/project.git'
+ true | 'git://example.com/group/group/project.git'
+ true | 'git://foo:bar@example.com/group/group/project.git'
+ true | 'http://foo:bar@example.com/group/group/project.git'
+ true | 'https://foo:bar@example.com/group/group/project.git'
+ end
- expect(filtered_content).to include("git://host.test/path/to/repo.git")
+ with_them do
+ it { expect(described_class.valid?(url)).to eq(value) }
end
+ end
+
+ describe '#sanitized_url' do
+ context 'credentials in hash' do
+ where(username: ['foo', '', nil], password: ['bar', '', nil])
- it 'does not modify scp-like URLs' do
- filtered_content = sanitize_url('user@server:project.git')
+ with_them do
+ let(:credentials) { { user: username, password: password } }
+ subject { described_class.new('http://example.com', credentials: credentials).sanitized_url }
- expect(filtered_content).to include("user@server:project.git")
+ it { is_expected.to eq('http://example.com') }
+ end
end
- it 'returns an empty string for invalid URLs' do
- filtered_content = sanitize_url('ssh://')
+ context 'credentials in URL' do
+ where(userinfo: %w[foo:bar@ foo@ :bar@ :@ @] + [nil])
- expect(filtered_content).to include("repository '' not found")
- end
- end
+ with_them do
+ subject { described_class.new("http://#{userinfo}example.com").sanitized_url }
- describe '.valid?' do
- it 'validates url strings' do
- expect(described_class.valid?(nil)).to be(false)
- expect(described_class.valid?('valid@project:url.git')).to be(true)
- expect(described_class.valid?('123://invalid:url')).to be(false)
+ it { is_expected.to eq('http://example.com') }
+ end
end
end
- describe '#sanitized_url' do
- it { expect(url_sanitizer.sanitized_url).to eq("https://github.com/me/project.git") }
- end
-
describe '#credentials' do
- it { expect(url_sanitizer.credentials).to eq(credentials) }
+ context 'credentials in hash' do
+ where(:input, :output) do
+ { user: 'foo', password: 'bar' } | { user: 'foo', password: 'bar' }
+ { user: 'foo', password: '' } | { user: 'foo', password: nil }
+ { user: 'foo', password: nil } | { user: 'foo', password: nil }
+ { user: '', password: 'bar' } | { user: nil, password: 'bar' }
+ { user: '', password: '' } | { user: nil, password: nil }
+ { user: '', password: nil } | { user: nil, password: nil }
+ { user: nil, password: 'bar' } | { user: nil, password: 'bar' }
+ { user: nil, password: '' } | { user: nil, password: nil }
+ { user: nil, password: nil } | { user: nil, password: nil }
+ end
- context 'when user is given to #initialize' do
- let(:url_sanitizer) do
- described_class.new("https://github.com/me/project.git", credentials: { user: user.username })
+ with_them do
+ subject { described_class.new('user@example.com:path.git', credentials: input).credentials }
+
+ it { is_expected.to eq(output) }
end
- it { expect(url_sanitizer.credentials).to eq({ user: 'john.doe' }) }
+ it 'overrides URL-provided credentials' do
+ sanitizer = described_class.new('http://a:b@example.com', credentials: { user: 'c', password: 'd' })
+
+ expect(sanitizer.credentials).to eq(user: 'c', password: 'd')
+ end
+ end
+
+ context 'credentials in URL' do
+ where(:url, :credentials) do
+ 'http://foo:bar@example.com' | { user: 'foo', password: 'bar' }
+ 'http://:bar@example.com' | { user: nil, password: 'bar' }
+ 'http://foo:@example.com' | { user: 'foo', password: nil }
+ 'http://foo@example.com' | { user: 'foo', password: nil }
+ 'http://:@example.com' | { user: nil, password: nil }
+ 'http://@example.com' | { user: nil, password: nil }
+ 'http://example.com' | { user: nil, password: nil }
+
+ # Credentials from SCP-style URLs are not supported at present
+ 'foo@example.com:path' | { user: nil, password: nil }
+ 'foo:bar@example.com:path' | { user: nil, password: nil }
+
+ # Other invalid URLs
+ nil | { user: nil, password: nil }
+ '' | { user: nil, password: nil }
+ 'no' | { user: nil, password: nil }
+ end
+
+ with_them do
+ subject { described_class.new(url).credentials }
+
+ it { is_expected.to eq(credentials) }
+ end
end
end
describe '#full_url' do
- it { expect(url_sanitizer.full_url).to eq("https://blah:password@github.com/me/project.git") }
+ context 'credentials in hash' do
+ where(:credentials, :userinfo) do
+ { user: 'foo', password: 'bar' } | 'foo:bar@'
+ { user: 'foo', password: '' } | 'foo@'
+ { user: 'foo', password: nil } | 'foo@'
+ { user: '', password: 'bar' } | ':bar@'
+ { user: '', password: '' } | nil
+ { user: '', password: nil } | nil
+ { user: nil, password: 'bar' } | ':bar@'
+ { user: nil, password: '' } | nil
+ { user: nil, password: nil } | nil
+ end
- it 'supports scp-like URLs' do
- sanitizer = described_class.new('user@server:project.git')
+ with_them do
+ subject { described_class.new('http://example.com', credentials: credentials).full_url }
- expect(sanitizer.full_url).to eq('user@server:project.git')
+ it { is_expected.to eq("http://#{userinfo}example.com") }
+ end
end
- context 'when user is given to #initialize' do
- let(:url_sanitizer) do
- described_class.new("https://github.com/me/project.git", credentials: { user: user.username })
+ context 'credentials in URL' do
+ where(:input, :output) do
+ nil | ''
+ '' | :same
+ 'git@example.com' | :same
+ 'http://example.com' | :same
+ 'http://foo@example.com' | :same
+ 'http://foo:@example.com' | 'http://foo@example.com'
+ 'http://:bar@example.com' | :same
+ 'http://foo:bar@example.com' | :same
end
- it { expect(url_sanitizer.full_url).to eq("https://john.doe@github.com/me/project.git") }
+ with_them do
+ let(:expected) { output == :same ? input : output }
+
+ it { expect(described_class.new(input).full_url).to eq(expected) }
+ end
end
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 37f6fd3a25b..fb5fb7daaab 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -480,4 +480,71 @@ describe Issuable do
end
end
end
+
+ describe '#first_contribution?' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+ let(:other_project) { create(:project) }
+ let(:owner) { create(:owner) }
+ let(:master) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:guest) { create(:user) }
+
+ let(:contributor) { create(:user) }
+ let(:first_time_contributor) { create(:user) }
+
+ before do
+ group.add_owner(owner)
+ project.add_master(master)
+ project.add_reporter(reporter)
+ project.add_guest(guest)
+ project.add_guest(contributor)
+ project.add_guest(first_time_contributor)
+ end
+
+ let(:merged_mr) { create(:merge_request, :merged, author: contributor, target_project: project, source_project: project) }
+ let(:open_mr) { create(:merge_request, author: first_time_contributor, target_project: project, source_project: project) }
+ let(:merged_mr_other_project) { create(:merge_request, :merged, author: first_time_contributor, target_project: other_project, source_project: other_project) }
+
+ context "for merge requests" do
+ it "is false for MASTER" do
+ mr = create(:merge_request, author: master, target_project: project, source_project: project)
+
+ expect(mr).not_to be_first_contribution
+ end
+
+ it "is false for OWNER" do
+ mr = create(:merge_request, author: owner, target_project: project, source_project: project)
+
+ expect(mr).not_to be_first_contribution
+ end
+
+ it "is false for REPORTER" do
+ mr = create(:merge_request, author: reporter, target_project: project, source_project: project)
+
+ expect(mr).not_to be_first_contribution
+ end
+
+ it "is true when you don't have any merged MR" do
+ expect(open_mr).to be_first_contribution
+ expect(merged_mr).not_to be_first_contribution
+ end
+
+ it "handles multiple projects separately" do
+ expect(open_mr).to be_first_contribution
+ expect(merged_mr_other_project).not_to be_first_contribution
+ end
+ end
+
+ context "for issues" do
+ let(:contributor_issue) { create(:issue, author: contributor, project: project) }
+ let(:first_time_contributor_issue) { create(:issue, author: first_time_contributor, project: project) }
+
+ it "is false even without merged MR" do
+ expect(merged_mr).to be
+ expect(first_time_contributor_issue).not_to be_first_contribution
+ expect(contributor_issue).not_to be_first_contribution
+ end
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index fd83a58ed9f..abf732e60bf 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2116,4 +2116,70 @@ describe User do
expect(user.verified_email?('other_email@example.com')).to be false
end
end
+
+ describe '#sync_attribute?' do
+ let(:user) { described_class.new }
+
+ context 'oauth user' do
+ it 'returns true if name can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(name location))
+ expect(user.sync_attribute?(:name)).to be_truthy
+ end
+
+ it 'returns true if email can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(name email))
+ expect(user.sync_attribute?(:email)).to be_truthy
+ end
+
+ it 'returns true if location can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:email)).to be_truthy
+ end
+
+ it 'returns false if name can not be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ end
+
+ it 'returns false if email can not be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ end
+
+ it 'returns false if location can not be synced' do
+ stub_omniauth_setting(sync_profile_attributes: %w(location email))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ end
+
+ it 'returns true for all syncable attributes if all syncable attributes can be synced' do
+ stub_omniauth_setting(sync_profile_attributes: true)
+ expect(user.sync_attribute?(:name)).to be_truthy
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_truthy
+ end
+
+ it 'returns false for all syncable attributes but email if no syncable attributes are declared' do
+ expect(user.sync_attribute?(:name)).to be_falsey
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_falsey
+ end
+ end
+
+ context 'ldap user' do
+ it 'returns true for email if ldap user' do
+ allow(user).to receive(:ldap_user?).and_return(true)
+ expect(user.sync_attribute?(:name)).to be_falsey
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_falsey
+ end
+
+ it 'returns true for email and location if ldap user and location declared as syncable' do
+ allow(user).to receive(:ldap_user?).and_return(true)
+ stub_omniauth_setting(sync_profile_attributes: %w(location))
+ expect(user.sync_attribute?(:name)).to be_falsey
+ expect(user.sync_attribute?(:email)).to be_truthy
+ expect(user.sync_attribute?(:location)).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index edbfaf510c5..f663719d28c 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -673,6 +673,12 @@ describe API::Commits do
it_behaves_like 'ref diff'
end
end
+
+ context 'when binary diff are treated as text' do
+ let(:commit_id) { TestEnv::BRANCH_SHA['add-pdf-text-binary'] }
+
+ it_behaves_like 'ref diff'
+ end
end
end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index a6c804fb2b3..1274e66bb4c 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -5,13 +5,26 @@ describe API::Internal do
let(:key) { create(:key, user: user) }
let(:project) { create(:project, :repository) }
let(:secret_token) { Gitlab::Shell.secret_token }
+ let(:gl_repository) { "project-#{project.id}" }
+ let(:reference_counter) { double('ReferenceCounter') }
describe "GET /internal/check" do
it do
+ expect_any_instance_of(Redis).to receive(:ping).and_return('PONG')
+
get api("/internal/check"), secret_token: secret_token
expect(response).to have_http_status(200)
expect(json_response['api_version']).to eq(API::API.version)
+ expect(json_response['redis']).to be(true)
+ end
+
+ it 'returns false for field `redis` when redis is unavailable' do
+ expect_any_instance_of(Redis).to receive(:ping).and_raise(Errno::ENOENT)
+
+ get api("/internal/check"), secret_token: secret_token
+
+ expect(json_response['redis']).to be(false)
end
end
@@ -661,9 +674,7 @@ describe API::Internal do
# end
describe 'POST /internal/post_receive' do
- let(:gl_repository) { "project-#{project.id}" }
let(:identifier) { 'key-123' }
- let(:reference_counter) { double('ReferenceCounter') }
let(:valid_params) do
{
@@ -749,6 +760,22 @@ describe API::Internal do
end
end
+ describe 'POST /internal/pre_receive' do
+ let(:valid_params) do
+ { gl_repository: gl_repository, secret_token: secret_token }
+ end
+
+ it 'decreases the reference counter and returns the result' do
+ expect(Gitlab::ReferenceCounter).to receive(:new).with(gl_repository)
+ .and_return(reference_counter)
+ expect(reference_counter).to receive(:increase).and_return(true)
+
+ post api("/internal/pre_receive"), valid_params
+
+ expect(json_response['reference_counter_increased']).to be(true)
+ end
+ end
+
def project_with_repo_path(path)
double().tap do |fake_project|
allow(fake_project).to receive_message_chain('repository.path_to_repo' => path)
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index f56baf9663d..2d7cc1a1798 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
describe API::Jobs do
- let!(:project) do
+ set(:project) do
create(:project, :repository, public_builds: false)
end
- let!(:pipeline) do
+ set(:pipeline) do
create(:ci_empty_pipeline, project: project,
sha: project.commit.id,
ref: project.default_branch)
@@ -188,6 +188,84 @@ describe API::Jobs do
end
end
+ describe 'GET /projects/:id/jobs/:job_id/artifacts/:artifact_path' do
+ context 'when job has artifacts' do
+ let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) }
+
+ let(:artifact) do
+ 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif'
+ end
+
+ context 'when user is anonymous' do
+ let(:api_user) { nil }
+
+ context 'when project is public' do
+ it 'allows to access artifacts' do
+ project.update_column(:visibility_level,
+ Gitlab::VisibilityLevel::PUBLIC)
+ project.update_column(:public_builds, true)
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when project is public with builds access disabled' do
+ it 'rejects access to artifacts' do
+ project.update_column(:visibility_level,
+ Gitlab::VisibilityLevel::PUBLIC)
+ project.update_column(:public_builds, false)
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(403)
+ end
+ end
+
+ context 'when project is private' do
+ it 'rejects access and hides existence of artifacts' do
+ project.update_column(:visibility_level,
+ Gitlab::VisibilityLevel::PRIVATE)
+ project.update_column(:public_builds, true)
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
+ context 'when user is authorized' do
+ it 'returns a specific artifact file for a valid path' do
+ expect(Gitlab::Workhorse)
+ .to receive(:send_artifacts_entry)
+ .and_call_original
+
+ get_artifact_file(artifact)
+
+ expect(response).to have_http_status(200)
+ expect(response.headers)
+ .to include('Content-Type' => 'application/json',
+ 'Gitlab-Workhorse-Send-Data' => /artifacts-entry/)
+ end
+ end
+ end
+
+ context 'when job does not have artifacts' do
+ it 'does not return job artifact file' do
+ get_artifact_file('some/artifact')
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ def get_artifact_file(artifact_path)
+ get api("/projects/#{project.id}/jobs/#{job.id}/" \
+ "artifacts/#{artifact_path}", api_user)
+ end
+ end
+
describe 'GET /projects/:id/jobs/:job_id/artifacts' do
before do
get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user)
@@ -209,11 +287,12 @@ describe API::Jobs do
end
end
- context 'unauthorized user' do
+ context 'when anonymous user is accessing private artifacts' do
let(:api_user) { nil }
- it 'does not return specific job artifacts' do
- expect(response).to have_http_status(401)
+ it 'hides artifacts and rejects request' do
+ expect(project).to be_private
+ expect(response).to have_http_status(404)
end
end
end
@@ -242,8 +321,9 @@ describe API::Jobs do
get_for_ref
end
- it 'gives 401' do
- expect(response).to have_http_status(401)
+ it 'does not find a resource in a private project' do
+ expect(project).to be_private
+ expect(response).to have_http_status(404)
end
end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index f5ed9ff608f..bbc3a8c79f5 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -52,6 +52,17 @@ describe Ci::RetryBuildService do
expect(new_build.send(attribute)).to eq build.send(attribute)
end
end
+
+ context 'when job has nullified protected' do
+ before do
+ build.update_attribute(:protected, nil)
+ end
+
+ it "clones protected build attribute" do
+ expect(new_build.protected).to be_nil
+ expect(new_build.protected).to eq build.protected
+ end
+ end
end
describe 'reject acessors' do
diff --git a/spec/support/seed_helper.rb b/spec/support/seed_helper.rb
index 8731847592b..11ef1fc477f 100644
--- a/spec/support/seed_helper.rb
+++ b/spec/support/seed_helper.rb
@@ -41,7 +41,7 @@ module SeedHelper
end
def create_mutable_seeds
- system(git_env, *%W(#{Gitlab.config.git.bin_path} clone #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}),
+ system(git_env, *%W(#{Gitlab.config.git.bin_path} clone --bare #{TEST_REPO_PATH} #{TEST_MUTABLE_REPO_PATH}),
chdir: SEED_STORAGE_PATH,
out: '/dev/null',
err: '/dev/null')