debian-mirror-gitlab/spec/lib/banzai/filter/repository_link_filter_spec.rb

378 lines
12 KiB
Ruby
Raw Normal View History

2019-10-12 21:52:04 +05:30
# frozen_string_literal: true
2015-12-23 02:04:40 +05:30
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec.describe Banzai::Filter::RepositoryLinkFilter do
2019-12-21 20:55:43 +05:30
include GitHelpers
include RepoHelpers
2015-12-23 02:04:40 +05:30
def filter(doc, contexts = {})
contexts.reverse_merge!({
2016-09-13 17:45:13 +05:30
commit: commit,
2015-12-23 02:04:40 +05:30
project: project,
2019-09-04 21:01:54 +05:30
current_user: user,
2018-03-17 18:26:18 +05:30
group: group,
2020-06-23 00:09:42 +05:30
wiki: wiki,
2015-12-23 02:04:40 +05:30
ref: ref,
2018-03-17 18:26:18 +05:30
requested_path: requested_path,
only_path: only_path
2015-12-23 02:04:40 +05:30
})
described_class.call(doc, contexts)
end
def image(path)
%(<img src="#{path}" />)
end
2016-08-24 12:49:21 +05:30
def video(path)
%(<video src="#{path}"></video>)
end
2019-12-21 20:55:43 +05:30
def audio(path)
%(<audio src="#{path}"></audio>)
end
2015-12-23 02:04:40 +05:30
def link(path)
%(<a href="#{path}">#{path}</a>)
end
2018-03-17 18:26:18 +05:30
def nested(element)
%(<div>#{element}</div>)
end
2019-12-21 20:55:43 +05:30
def allow_gitaly_n_plus_1
Gitlab::GitalyClient.allow_n_plus_1_calls do
yield
end
end
2019-09-04 21:01:54 +05:30
let(:project) { create(:project, :repository, :public) }
let(:user) { create(:user) }
2018-03-17 18:26:18 +05:30
let(:group) { nil }
2017-09-10 17:25:29 +05:30
let(:project_path) { project.full_path }
2015-12-23 02:04:40 +05:30
let(:ref) { 'markdown' }
2016-09-13 17:45:13 +05:30
let(:commit) { project.commit(ref) }
2020-06-23 00:09:42 +05:30
let(:wiki) { nil }
2015-12-23 02:04:40 +05:30
let(:requested_path) { '/' }
2018-03-17 18:26:18 +05:30
let(:only_path) { true }
2015-12-23 02:04:40 +05:30
2019-12-21 20:55:43 +05:30
it 'does not trigger a gitaly n+1', :request_store do
raw_doc = ""
allow_gitaly_n_plus_1 do
30.times do |i|
create_file_in_repo(project, ref, ref, "new_file_#{i}", "x" )
raw_doc += link("new_file_#{i}")
end
end
expect { filter(raw_doc) }.to change { Gitlab::GitalyClient.get_request_count }.by(2)
end
2015-12-23 02:04:40 +05:30
shared_examples :preserve_unchanged do
it 'does not modify any relative URL in anchor' do
doc = filter(link('README.md'))
expect(doc.at_css('a')['href']).to eq 'README.md'
end
it 'does not modify any relative URL in image' do
doc = filter(image('files/images/logo-black.png'))
expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
end
2016-08-24 12:49:21 +05:30
it 'does not modify any relative URL in video' do
doc = filter(video('files/videos/intro.mp4'), commit: project.commit('video'), ref: 'video')
expect(doc.at_css('video')['src']).to eq 'files/videos/intro.mp4'
end
2019-12-21 20:55:43 +05:30
it 'does not modify any relative URL in audio' do
doc = filter(audio('files/audio/sample.wav'), commit: project.commit('audio'), ref: 'audio')
expect(doc.at_css('audio')['src']).to eq 'files/audio/sample.wav'
end
2015-12-23 02:04:40 +05:30
end
2020-06-23 00:09:42 +05:30
context 'with a wiki' do
let(:wiki) { double('ProjectWiki') }
2020-01-01 13:55:28 +05:30
2015-12-23 02:04:40 +05:30
include_examples :preserve_unchanged
end
context 'without a repository' do
2017-09-10 17:25:29 +05:30
let(:project) { create(:project) }
2020-01-01 13:55:28 +05:30
2015-12-23 02:04:40 +05:30
include_examples :preserve_unchanged
end
context 'with an empty repository' do
let(:project) { create(:project_empty_repo) }
2020-01-01 13:55:28 +05:30
2015-12-23 02:04:40 +05:30
include_examples :preserve_unchanged
end
2019-09-04 21:01:54 +05:30
context 'without project repository access' do
let(:project) { create(:project, :repository, repository_access_level: ProjectFeature::PRIVATE) }
2020-01-01 13:55:28 +05:30
2019-09-04 21:01:54 +05:30
include_examples :preserve_unchanged
end
2015-12-23 02:04:40 +05:30
it 'does not raise an exception on invalid URIs' do
act = link("://foo")
expect { filter(act) }.not_to raise_error
end
2019-12-04 20:38:33 +05:30
it 'does not raise an exception on URIs containing invalid utf-8 byte sequences' do
act = link("%FF")
expect { filter(act) }.not_to raise_error
end
2020-01-03 18:37:03 +05:30
it 'does not raise an exception on URIs containing invalid utf-8 byte sequences in context requested path' do
expect { filter(link("files/test.md"), requested_path: '%FF') }.not_to raise_error
end
2018-03-17 18:26:18 +05:30
it 'does not raise an exception with a garbled path' do
act = link("open(/var/tmp/):%20/location%0Afrom:%20/test")
expect { filter(act) }.not_to raise_error
end
2019-07-07 11:18:12 +05:30
it 'does not explode with an escaped null byte' do
act = link("/%00")
expect { filter(act) }.not_to raise_error
end
2016-09-13 17:45:13 +05:30
it 'ignores ref if commit is passed' do
doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') )
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-04-08 14:13:33 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/non/existent.file"
2016-09-13 17:45:13 +05:30
end
shared_examples :valid_repository do
2020-04-08 14:13:33 +05:30
it 'handles Gitaly unavailable exceptions gracefully' do
allow_next_instance_of(Gitlab::GitalyClient::BlobService) do |blob_service|
allow(blob_service).to receive(:get_blob_types).and_raise(GRPC::Unavailable)
end
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
an_instance_of(GRPC::Unavailable), project_id: project.id
)
doc = ""
expect { doc = filter(link('doc/api/README.md')) }.not_to raise_error
expect(doc.at_css('a')['href'])
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
end
it 'handles Gitaly timeout exceptions gracefully' do
allow_next_instance_of(Gitlab::GitalyClient::BlobService) do |blob_service|
allow(blob_service).to receive(:get_blob_types).and_raise(GRPC::DeadlineExceeded)
end
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
an_instance_of(GRPC::DeadlineExceeded), project_id: project.id
)
doc = ""
expect { doc = filter(link('doc/api/README.md')) }.not_to raise_error
expect(doc.at_css('a')['href'])
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
end
2016-09-13 17:45:13 +05:30
it 'rebuilds absolute URL for a file in the repo' do
doc = filter(link('/doc/api/README.md'))
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
2016-09-13 17:45:13 +05:30
end
2019-09-04 21:01:54 +05:30
it 'does not modify relative URLs in system notes' do
2020-03-13 15:44:24 +05:30
path = "#{project_path}/-/merge_requests/1/diffs"
2019-09-04 21:01:54 +05:30
doc = filter(link(path), system_note: true)
expect(doc.at_css('a')['href']).to eq path
end
2016-09-13 17:45:13 +05:30
it 'ignores absolute URLs with two leading slashes' do
doc = filter(link('//doc/api/README.md'))
expect(doc.at_css('a')['href']).to eq '//doc/api/README.md'
end
2015-12-23 02:04:40 +05:30
it 'rebuilds relative URL for a file in the repo' do
doc = filter(link('doc/api/README.md'))
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
2015-12-23 02:04:40 +05:30
end
2020-04-08 14:13:33 +05:30
it 'rebuilds relative URL for a missing file in the repo' do
doc = filter(link('missing-file'))
expect(doc.at_css('a')['href'])
.to eq "/#{project_path}/-/blob/#{ref}/missing-file"
end
2016-09-13 17:45:13 +05:30
it 'rebuilds relative URL for a file in the repo with leading ./' do
doc = filter(link('./doc/api/README.md'))
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
2016-09-13 17:45:13 +05:30
end
2015-12-23 02:04:40 +05:30
it 'rebuilds relative URL for a file in the repo up one directory' do
relative_link = link('../api/README.md')
doc = filter(relative_link, requested_path: 'doc/update/7.14-to-8.0.md')
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
2015-12-23 02:04:40 +05:30
end
it 'rebuilds relative URL for a file in the repo up multiple directories' do
relative_link = link('../../../api/README.md')
doc = filter(relative_link, requested_path: 'doc/foo/bar/baz/README.md')
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
2015-12-23 02:04:40 +05:30
end
it 'rebuilds relative URL for a file in the repository root' do
relative_link = link('../README.md')
doc = filter(relative_link, requested_path: 'doc/some-file.md')
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/README.md"
end
2015-12-23 02:04:40 +05:30
it 'rebuilds relative URL for a file in the repo with an anchor' do
doc = filter(link('README.md#section'))
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/blob/#{ref}/README.md#section"
2015-12-23 02:04:40 +05:30
end
it 'rebuilds relative URL for a directory in the repo' do
doc = filter(link('doc/api/'))
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/tree/#{ref}/doc/api"
2015-12-23 02:04:40 +05:30
end
it 'rebuilds relative URL for an image in the repo' do
2016-08-24 12:49:21 +05:30
doc = filter(image('files/images/logo-black.png'))
2017-09-10 17:25:29 +05:30
expect(doc.at_css('img')['src'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/raw/#{ref}/files/images/logo-black.png"
2016-08-24 12:49:21 +05:30
end
it 'rebuilds relative URL for link to an image in the repo' do
2015-12-23 02:04:40 +05:30
doc = filter(link('files/images/logo-black.png'))
2016-08-24 12:49:21 +05:30
2017-09-10 17:25:29 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/raw/#{ref}/files/images/logo-black.png"
2015-12-23 02:04:40 +05:30
end
2016-08-24 12:49:21 +05:30
it 'rebuilds relative URL for a video in the repo' do
doc = filter(video('files/videos/intro.mp4'), commit: project.commit('video'), ref: 'video')
2017-09-10 17:25:29 +05:30
expect(doc.at_css('video')['src'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/raw/video/files/videos/intro.mp4"
2016-08-24 12:49:21 +05:30
end
2019-12-21 20:55:43 +05:30
it 'rebuilds relative URL for audio in the repo' do
doc = filter(audio('files/audio/sample.wav'), commit: project.commit('audio'), ref: 'audio')
expect(doc.at_css('audio')['src'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/raw/audio/files/audio/sample.wav"
2019-12-21 20:55:43 +05:30
end
2015-12-23 02:04:40 +05:30
it 'does not modify relative URL with an anchor only' do
doc = filter(link('#section-1'))
expect(doc.at_css('a')['href']).to eq '#section-1'
end
it 'does not modify absolute URL' do
doc = filter(link('http://example.com'))
expect(doc.at_css('a')['href']).to eq 'http://example.com'
end
2019-12-21 20:55:43 +05:30
it 'does not call gitaly' do
filter(link('http://example.com'))
expect(described_class).not_to receive(:get_blob_types)
end
2015-12-23 02:04:40 +05:30
it 'supports Unicode filenames' do
path = 'files/images/한글.png'
escaped = Addressable::URI.escape(path)
2016-06-22 15:30:34 +05:30
# Stub this method so the file doesn't actually need to be in the repo
allow_any_instance_of(described_class).to receive(:uri_type).and_return(:raw)
2015-12-23 02:04:40 +05:30
doc = filter(image(escaped))
2020-03-13 15:44:24 +05:30
expect(doc.at_css('img')['src']).to eq "/#{project_path}/-/raw/#{Addressable::URI.escape(ref)}/#{escaped}"
2015-12-23 02:04:40 +05:30
end
context 'when requested path is a file in the repo' do
let(:requested_path) { 'doc/api/README.md' }
2020-01-01 13:55:28 +05:30
2017-08-17 22:00:37 +05:30
it 'rebuilds URL relative to the containing directory' do
doc = filter(link('users.md'))
2020-03-13 15:44:24 +05:30
expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/doc/api/users.md"
2017-08-17 22:00:37 +05:30
end
2015-12-23 02:04:40 +05:30
end
context 'when requested path is a directory in the repo' do
2017-08-17 22:00:37 +05:30
let(:requested_path) { 'doc/api/' }
2020-01-01 13:55:28 +05:30
2017-08-17 22:00:37 +05:30
it 'rebuilds URL relative to the directory' do
doc = filter(link('users.md'))
2020-03-13 15:44:24 +05:30
expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/doc/api/users.md"
2017-08-17 22:00:37 +05:30
end
end
context 'when ref name contains percent sign' do
let(:ref) { '100%branch' }
let(:commit) { project.commit('1b12f15a11fc6e62177bef08f47bc7b5ce50b141') }
let(:requested_path) { 'foo/bar/' }
2020-01-01 13:55:28 +05:30
2017-08-17 22:00:37 +05:30
it 'correctly escapes the ref' do
doc = filter(link('.gitkeep'))
2020-03-13 15:44:24 +05:30
expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/foo/bar/.gitkeep"
2017-08-17 22:00:37 +05:30
end
end
2018-05-09 12:01:36 +05:30
context 'when ref name contains special chars' do
2019-12-21 20:55:43 +05:30
let(:ref) { 'mark#\'@],+;-._/#@!$&()+down' }
let(:path) { 'files/images/logo-black.png' }
2018-05-09 12:01:36 +05:30
it 'correctly escapes the ref' do
2018-12-13 13:39:08 +05:30
# Addressable won't escape the '#', so we do this manually
2018-05-09 12:01:36 +05:30
ref_escaped = 'mark%23\'@%5D,+;-._/%23@!$&()+down'
# Stub this method so the branch doesn't actually need to be in the repo
allow_any_instance_of(described_class).to receive(:uri_type).and_return(:raw)
2019-12-21 20:55:43 +05:30
allow_any_instance_of(described_class).to receive(:get_uri_types).and_return({ path: :tree })
2018-05-09 12:01:36 +05:30
2019-12-21 20:55:43 +05:30
doc = filter(link(path))
2018-05-09 12:01:36 +05:30
expect(doc.at_css('a')['href'])
2020-03-13 15:44:24 +05:30
.to eq "/#{project_path}/-/raw/#{ref_escaped}/files/images/logo-black.png"
2018-05-09 12:01:36 +05:30
end
end
2017-08-17 22:00:37 +05:30
context 'when requested path is a directory with space in the repo' do
let(:ref) { 'master' }
let(:commit) { project.commit('38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e') }
let(:requested_path) { 'with space/' }
2020-01-01 13:55:28 +05:30
2017-08-17 22:00:37 +05:30
it 'does not escape the space twice' do
doc = filter(link('README.md'))
2020-03-13 15:44:24 +05:30
expect(doc.at_css('a')['href']).to eq "/#{project_path}/-/blob/#{Addressable::URI.escape(ref)}/with%20space/README.md"
2017-08-17 22:00:37 +05:30
end
2015-12-23 02:04:40 +05:30
end
end
2016-09-13 17:45:13 +05:30
context 'with a valid commit' do
include_examples :valid_repository
end
context 'with a valid ref' do
2020-01-01 13:55:28 +05:30
# force filter to use ref instead of commit
let(:commit) { nil }
2016-09-13 17:45:13 +05:30
include_examples :valid_repository
end
2015-12-23 02:04:40 +05:30
end