Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-05-19 18:44:42 +0300
commit4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch)
tree5423a1c7516cffe36384133ade12572cf709398d /spec/lib/banzai
parente570267f2f6b326480d284e0164a6464ba4081bc (diff)
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'spec/lib/banzai')
-rw-r--r--spec/lib/banzai/cross_project_reference_spec.rb15
-rw-r--r--spec/lib/banzai/filter/custom_emoji_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/references/abstract_reference_filter_spec.rb80
-rw-r--r--spec/lib/banzai/filter/references/design_reference_filter_spec.rb6
-rw-r--r--spec/lib/banzai/filter/references/issue_reference_filter_spec.rb24
-rw-r--r--spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb11
-rw-r--r--spec/lib/banzai/filter/references/project_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/references/reference_cache_spec.rb144
-rw-r--r--spec/lib/banzai/filter/references/reference_filter_spec.rb27
-rw-r--r--spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb27
-rw-r--r--spec/lib/banzai/filter/references/user_reference_filter_spec.rb25
-rw-r--r--spec/lib/banzai/pipeline/post_process_pipeline_spec.rb54
-rw-r--r--spec/lib/banzai/reference_parser/merge_request_parser_spec.rb47
13 files changed, 348 insertions, 118 deletions
diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb
index 95b78ceb5d5..60ff15a88e0 100644
--- a/spec/lib/banzai/cross_project_reference_spec.rb
+++ b/spec/lib/banzai/cross_project_reference_spec.rb
@@ -4,10 +4,12 @@ require 'spec_helper'
RSpec.describe Banzai::CrossProjectReference do
let(:including_class) { Class.new.include(described_class).new }
+ let(:reference_cache) { Banzai::Filter::References::ReferenceCache.new(including_class, {})}
before do
allow(including_class).to receive(:context).and_return({})
allow(including_class).to receive(:parent_from_ref).and_call_original
+ allow(including_class).to receive(:reference_cache).and_return(reference_cache)
end
describe '#parent_from_ref' do
@@ -47,5 +49,18 @@ RSpec.describe Banzai::CrossProjectReference do
expect(including_class.parent_from_ref('cross/reference')).to eq project2
end
end
+
+ context 'when reference cache is loaded' do
+ let(:project2) { double('referenced project') }
+
+ before do
+ allow(reference_cache).to receive(:cache_loaded?).and_return(true)
+ allow(reference_cache).to receive(:parent_per_reference).and_return({ 'cross/reference' => project2 })
+ end
+
+ it 'pulls from the reference cache' do
+ expect(including_class.parent_from_ref('cross/reference')).to eq project2
+ end
+ end
end
end
diff --git a/spec/lib/banzai/filter/custom_emoji_filter_spec.rb b/spec/lib/banzai/filter/custom_emoji_filter_spec.rb
index 5e76e8164dd..94e77663d0f 100644
--- a/spec/lib/banzai/filter/custom_emoji_filter_spec.rb
+++ b/spec/lib/banzai/filter/custom_emoji_filter_spec.rb
@@ -53,7 +53,7 @@ RSpec.describe Banzai::Filter::CustomEmojiFilter do
end
expect do
- filter('<p>:tanuki: :party-parrot:</p>')
+ filter('<p>:tanuki:</p> <p>:party-parrot:</p>')
end.not_to exceed_all_query_limit(control_count.count)
end
end
diff --git a/spec/lib/banzai/filter/references/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/references/abstract_reference_filter_spec.rb
index 076c112ac87..3cb3ebc42a6 100644
--- a/spec/lib/banzai/filter/references/abstract_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/abstract_reference_filter_spec.rb
@@ -8,18 +8,6 @@ RSpec.describe Banzai::Filter::References::AbstractReferenceFilter do
let(:doc) { Nokogiri::HTML.fragment('') }
let(:filter) { described_class.new(doc, project: project) }
- describe '#references_per_parent' do
- let(:doc) { Nokogiri::HTML.fragment("#1 #{project.full_path}#2 #2") }
-
- it 'returns a Hash containing references grouped per parent paths' do
- expect(described_class).to receive(:object_class).exactly(6).times.and_return(Issue)
-
- refs = filter.references_per_parent
-
- expect(refs).to match(a_hash_including(project.full_path => contain_exactly(1, 2)))
- end
- end
-
describe '#data_attributes_for' do
let_it_be(:issue) { create(:issue, project: project) }
@@ -32,71 +20,17 @@ RSpec.describe Banzai::Filter::References::AbstractReferenceFilter do
end
end
- describe '#parent_per_reference' do
- it 'returns a Hash containing projects grouped per parent paths' do
- expect(filter).to receive(:references_per_parent)
- .and_return({ project.full_path => Set.new([1]) })
-
- expect(filter.parent_per_reference)
- .to eq({ project.full_path => project })
- end
- end
-
- describe '#find_for_paths' do
- context 'with RequestStore disabled' do
- it 'returns a list of Projects for a list of paths' do
- expect(filter.find_for_paths([project.full_path]))
- .to eq([project])
- end
-
- it "return an empty array for paths that don't exist" do
- expect(filter.find_for_paths(['nonexistent/project']))
- .to eq([])
+ context 'abstract methods' do
+ describe '#find_object' do
+ it 'raises NotImplementedError' do
+ expect { filter.find_object(nil, nil) }.to raise_error(NotImplementedError)
end
end
- context 'with RequestStore enabled', :request_store do
- it 'returns a list of Projects for a list of paths' do
- expect(filter.find_for_paths([project.full_path]))
- .to eq([project])
+ describe '#url_for_object' do
+ it 'raises NotImplementedError' do
+ expect { filter.url_for_object(nil, nil) }.to raise_error(NotImplementedError)
end
-
- context "when no project with that path exists" do
- it "returns no value" do
- expect(filter.find_for_paths(['nonexistent/project']))
- .to eq([])
- end
-
- it "adds the ref to the project refs cache" do
- project_refs_cache = {}
- allow(filter).to receive(:refs_cache).and_return(project_refs_cache)
-
- filter.find_for_paths(['nonexistent/project'])
-
- expect(project_refs_cache).to eq({ 'nonexistent/project' => nil })
- end
-
- context 'when the project refs cache includes nil values' do
- before do
- # adds { 'nonexistent/project' => nil } to cache
- filter.from_ref_cached('nonexistent/project')
- end
-
- it "return an empty array for paths that don't exist" do
- expect(filter.find_for_paths(['nonexistent/project']))
- .to eq([])
- end
- end
- end
- end
- end
-
- describe '#current_parent_path' do
- it 'returns the path of the current parent' do
- doc = Nokogiri::HTML.fragment('')
- filter = described_class.new(doc, project: project)
-
- expect(filter.current_parent_path).to eq(project.full_path)
end
end
end
diff --git a/spec/lib/banzai/filter/references/design_reference_filter_spec.rb b/spec/lib/banzai/filter/references/design_reference_filter_spec.rb
index 52514ad17fc..cb1f3d520a4 100644
--- a/spec/lib/banzai/filter/references/design_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/design_reference_filter_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
let(:pattern) { described_class.object_class.link_reference_pattern }
let(:parsed) do
m = pattern.match(url)
- described_class.identifier(m) if m
+ described_class.new('', project: nil).identifier(m) if m
end
it 'can parse the reference' do
@@ -119,9 +119,11 @@ RSpec.describe Banzai::Filter::References::DesignReferenceFilter do
describe 'static properties' do
specify do
expect(described_class).to have_attributes(
- object_sym: :design,
+ reference_type: :design,
object_class: ::DesignManagement::Design
)
+
+ expect(described_class.new('', project: nil).object_sym).to eq :design
end
end
diff --git a/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
index b849355f6db..88c2494b243 100644
--- a/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
@@ -470,42 +470,24 @@ RSpec.describe Banzai::Filter::References::IssueReferenceFilter do
end
end
- describe '#records_per_parent' do
- context 'using an internal issue tracker' do
- it 'returns a Hash containing the issues per project' do
- doc = Nokogiri::HTML.fragment('')
- filter = described_class.new(doc, project: project)
-
- expect(filter).to receive(:parent_per_reference)
- .and_return({ project.full_path => project })
-
- expect(filter).to receive(:references_per_parent)
- .and_return({ project.full_path => Set.new([issue.iid]) })
-
- expect(filter.records_per_parent)
- .to eq({ project => { issue.iid => issue } })
- end
- end
- end
-
describe '.references_in' do
let(:merge_request) { create(:merge_request) }
it 'yields valid references' do
expect do |b|
- described_class.references_in(issue.to_reference, &b)
+ described_class.new('', project: nil).references_in(issue.to_reference, &b)
end.to yield_with_args(issue.to_reference, issue.iid, nil, nil, MatchData)
end
it "doesn't yield invalid references" do
expect do |b|
- described_class.references_in('#0', &b)
+ described_class.new('', project: nil).references_in('#0', &b)
end.not_to yield_control
end
it "doesn't yield unsupported references" do
expect do |b|
- described_class.references_in(merge_request.to_reference, &b)
+ described_class.new('', project: nil).references_in(merge_request.to_reference, &b)
end.not_to yield_control
end
end
diff --git a/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb
index 7a634b0b513..ee2ce967a47 100644
--- a/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb
@@ -142,6 +142,17 @@ RSpec.describe Banzai::Filter::References::MergeRequestReferenceFilter do
expect(doc.text).to eq("Merge (#{reference}.)")
end
+ it 'has correct data attributes' do
+ doc = reference_filter("Merge (#{reference}.)")
+
+ link = doc.css('a').first
+
+ expect(link.attr('data-project')).to eq project2.id.to_s
+ expect(link.attr('data-project-path')).to eq project2.full_path
+ expect(link.attr('data-iid')).to eq merge.iid.to_s
+ expect(link.attr('data-mr-title')).to eq merge.title
+ end
+
it 'ignores invalid merge IDs on the referenced project' do
exp = act = "Merge #{invalidate_reference(reference)}"
diff --git a/spec/lib/banzai/filter/references/project_reference_filter_spec.rb b/spec/lib/banzai/filter/references/project_reference_filter_spec.rb
index 7a77d57cd42..63a5a9184c1 100644
--- a/spec/lib/banzai/filter/references/project_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/project_reference_filter_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter do
document = Nokogiri::HTML.fragment("<p>#{get_reference(project)}</p>")
filter = described_class.new(document, project: project)
- expect(filter.projects_hash).to eq({ project.full_path => project })
+ expect(filter.send(:projects_hash)).to eq({ project.full_path => project })
end
end
@@ -94,7 +94,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter do
document = Nokogiri::HTML.fragment("<p>#{get_reference(project)}</p>")
filter = described_class.new(document, project: project)
- expect(filter.projects).to eq([project.full_path])
+ expect(filter.send(:projects)).to eq([project.full_path])
end
end
end
diff --git a/spec/lib/banzai/filter/references/reference_cache_spec.rb b/spec/lib/banzai/filter/references/reference_cache_spec.rb
new file mode 100644
index 00000000000..9e2a6f35910
--- /dev/null
+++ b/spec/lib/banzai/filter/references/reference_cache_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Banzai::Filter::References::ReferenceCache do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:issue1) { create(:issue, project: project) }
+ let_it_be(:issue2) { create(:issue, project: project) }
+ let_it_be(:issue3) { create(:issue, project: project2) }
+ let_it_be(:doc) { Nokogiri::HTML.fragment("#{issue1.to_reference} #{issue2.to_reference} #{issue3.to_reference(full: true)}") }
+
+ let(:filter_class) { Banzai::Filter::References::IssueReferenceFilter }
+ let(:filter) { filter_class.new(doc, project: project) }
+ let(:cache) { described_class.new(filter, { project: project }) }
+
+ describe '#load_references_per_parent' do
+ it 'loads references grouped per parent paths' do
+ cache.load_references_per_parent(filter.nodes)
+
+ expect(cache.references_per_parent).to eq({ project.full_path => [issue1.iid, issue2.iid].to_set,
+ project2.full_path => [issue3.iid].to_set })
+ end
+ end
+
+ describe '#load_parent_per_reference' do
+ it 'returns a Hash containing projects grouped per parent paths' do
+ cache.load_references_per_parent(filter.nodes)
+ cache.load_parent_per_reference
+
+ expect(cache.parent_per_reference).to match({ project.full_path => project, project2.full_path => project2 })
+ end
+ end
+
+ describe '#load_records_per_parent' do
+ it 'returns a Hash containing projects grouped per parent paths' do
+ cache.load_references_per_parent(filter.nodes)
+ cache.load_parent_per_reference
+ cache.load_records_per_parent
+
+ expect(cache.records_per_parent).to match({ project => { issue1.iid => issue1, issue2.iid => issue2 },
+ project2 => { issue3.iid => issue3 } })
+ end
+ end
+
+ describe '#initialize_reference_cache' do
+ it 'does not have an N+1 query problem with cross projects' do
+ doc_single = Nokogiri::HTML.fragment("#1")
+ filter_single = filter_class.new(doc_single, project: project)
+ cache_single = described_class.new(filter_single, { project: project })
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ cache_single.load_references_per_parent(filter_single.nodes)
+ cache_single.load_parent_per_reference
+ cache_single.load_records_per_parent
+ end.count
+
+ # Since this is an issue filter that is not batching issue queries
+ # across projects, we have to account for that.
+ # 1 for both projects, 1 for issues in each project == 3
+ # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/330359
+ max_count = control_count + 1
+
+ expect do
+ cache.load_references_per_parent(filter.nodes)
+ cache.load_parent_per_reference
+ cache.load_records_per_parent
+ end.not_to exceed_query_limit(max_count)
+ end
+ end
+
+ describe '#find_for_paths' do
+ context 'with RequestStore disabled' do
+ it 'returns a list of Projects for a list of paths' do
+ expect(cache.find_for_paths([project.full_path]))
+ .to eq([project])
+ end
+
+ it 'return an empty array for paths that do not exist' do
+ expect(cache.find_for_paths(['nonexistent/project']))
+ .to eq([])
+ end
+ end
+
+ context 'with RequestStore enabled', :request_store do
+ it 'returns a list of Projects for a list of paths' do
+ expect(cache.find_for_paths([project.full_path]))
+ .to eq([project])
+ end
+
+ context 'when no project with that path exists' do
+ it 'returns no value' do
+ expect(cache.find_for_paths(['nonexistent/project']))
+ .to eq([])
+ end
+
+ it 'adds the ref to the project refs cache' do
+ project_refs_cache = {}
+ allow(cache).to receive(:refs_cache).and_return(project_refs_cache)
+
+ cache.find_for_paths(['nonexistent/project'])
+
+ expect(project_refs_cache).to eq({ 'nonexistent/project' => nil })
+ end
+ end
+ end
+ end
+
+ describe '#current_parent_path' do
+ it 'returns the path of the current parent' do
+ expect(cache.current_parent_path).to eq project.full_path
+ end
+ end
+
+ describe '#current_project_namespace_path' do
+ it 'returns the path of the current project namespace' do
+ expect(cache.current_project_namespace_path).to eq project.namespace.full_path
+ end
+ end
+
+ describe '#full_project_path' do
+ it 'returns current parent path when no ref specified' do
+ expect(cache.full_project_path('something', nil)).to eq cache.current_parent_path
+ end
+
+ it 'returns combined namespace and project ref' do
+ expect(cache.full_project_path('something', 'cool')).to eq 'something/cool'
+ end
+
+ it 'returns uses default namespace and project ref when namespace nil' do
+ expect(cache.full_project_path(nil, 'cool')).to eq "#{project.namespace.full_path}/cool"
+ end
+ end
+
+ describe '#full_group_path' do
+ it 'returns current parent path when no group ref specified' do
+ expect(cache.full_group_path(nil)).to eq cache.current_parent_path
+ end
+
+ it 'returns group ref' do
+ expect(cache.full_group_path('cool_group')).to eq 'cool_group'
+ end
+ end
+end
diff --git a/spec/lib/banzai/filter/references/reference_filter_spec.rb b/spec/lib/banzai/filter/references/reference_filter_spec.rb
index 4bcb41ef2a9..b14b9374364 100644
--- a/spec/lib/banzai/filter/references/reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/reference_filter_spec.rb
@@ -155,7 +155,7 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
let(:nodes) { [node] }
it 'skips node' do
- expect { |b| filter.replace_text_when_pattern_matches(filter.nodes[0], 0, ref_pattern, &b) }.not_to yield_control
+ expect { |b| filter.send(:replace_text_when_pattern_matches, filter.nodes[0], 0, ref_pattern, &b) }.not_to yield_control
end
end
@@ -183,12 +183,12 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
end
end
- describe "#call_and_update_nodes" do
+ describe '#call_and_update_nodes' do
include_context 'new nodes'
let(:document) { Nokogiri::HTML.fragment('<a href="foo">foo</a>') }
let(:filter) { described_class.new(document, project: project) }
- it "updates all new nodes", :aggregate_failures do
+ it 'updates all new nodes', :aggregate_failures do
filter.instance_variable_set('@nodes', nodes)
expect(filter).to receive(:call) { filter.instance_variable_set('@new_nodes', new_nodes) }
@@ -201,14 +201,14 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
end
end
- describe ".call" do
+ describe '.call' do
include_context 'new nodes'
let(:document) { Nokogiri::HTML.fragment('<a href="foo">foo</a>') }
let(:result) { { reference_filter_nodes: nodes } }
- it "updates all nodes", :aggregate_failures do
+ it 'updates all nodes', :aggregate_failures do
expect_next_instance_of(described_class) do |filter|
expect(filter).to receive(:call_and_update_nodes).and_call_original
expect(filter).to receive(:with_update_nodes).and_call_original
@@ -221,4 +221,21 @@ RSpec.describe Banzai::Filter::References::ReferenceFilter do
expect(result[:reference_filter_nodes]).to eq(expected_nodes)
end
end
+
+ context 'abstract methods' do
+ let(:document) { Nokogiri::HTML.fragment('<a href="foo">foo</a>') }
+ let(:filter) { described_class.new(document, project: project) }
+
+ describe '#references_in' do
+ it 'raises NotImplementedError' do
+ expect { filter.references_in('foo', %r{(?<!\w)}) }.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '#object_link_filter' do
+ it 'raises NotImplementedError' do
+ expect { filter.send(:object_link_filter, 'foo', %r{(?<!\w)}) }.to raise_error(NotImplementedError)
+ end
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb
index 32a706925ba..7ab3b24b1c2 100644
--- a/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb
@@ -219,4 +219,31 @@ RSpec.describe Banzai::Filter::References::SnippetReferenceFilter do
expect(reference_filter(act, project: nil, group: create(:group)).to_html).to eq exp
end
end
+
+ context 'checking N+1' do
+ let(:namespace2) { create(:namespace) }
+ let(:project2) { create(:project, :public, namespace: namespace2) }
+ let(:snippet2) { create(:project_snippet, project: project2) }
+ let(:reference2) { "#{project2.full_path}$#{snippet2.id}" }
+
+ it 'does not have N+1 per multiple references per project', :use_sql_query_cache do
+ markdown = "#{reference} $9999990"
+
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ reference_filter(markdown)
+ end.count
+
+ markdown = "#{reference} $9999990 $9999991 $9999992 $9999993 #{reference2} something/cool$12"
+
+ # Since we're not batching snippet queries across projects,
+ # we have to account for that.
+ # 1 for both projects, 1 for snippets in each project == 3
+ # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/330359
+ max_count = control_count + 1
+
+ expect do
+ reference_filter(markdown)
+ end.not_to exceed_all_query_limit(max_count)
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/references/user_reference_filter_spec.rb b/spec/lib/banzai/filter/references/user_reference_filter_spec.rb
index e4703606b47..70cbdb080a4 100644
--- a/spec/lib/banzai/filter/references/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/user_reference_filter_spec.rb
@@ -189,7 +189,7 @@ RSpec.describe Banzai::Filter::References::UserReferenceFilter do
filter = described_class.new(document, project: project)
ns = user.namespace
- expect(filter.namespaces).to eq({ ns.path => ns })
+ expect(filter.send(:namespaces)).to eq({ ns.path => ns })
end
end
@@ -198,7 +198,28 @@ RSpec.describe Banzai::Filter::References::UserReferenceFilter do
document = Nokogiri::HTML.fragment("<p>#{get_reference(user)}</p>")
filter = described_class.new(document, project: project)
- expect(filter.usernames).to eq([user.username])
+ expect(filter.send(:usernames)).to eq([user.username])
+ end
+ end
+
+ context 'checking N+1' do
+ let(:user2) { create(:user) }
+ let(:group) { create(:group) }
+ let(:reference2) { user2.to_reference }
+ let(:reference3) { group.to_reference }
+
+ it 'does not have N+1 per multiple user references', :use_sql_query_cache do
+ markdown = "#{reference}"
+
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ reference_filter(markdown)
+ end.count
+
+ markdown = "#{reference} @qwertyuiopzx @wertyuio @ertyu @rtyui #{reference2} #{reference3}"
+
+ expect do
+ reference_filter(markdown)
+ end.not_to exceed_all_query_limit(control_count)
end
end
end
diff --git a/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb b/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb
index d9f45769550..ebe1ca4d403 100644
--- a/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/post_process_pipeline_spec.rb
@@ -3,24 +3,56 @@
require 'spec_helper'
RSpec.describe Banzai::Pipeline::PostProcessPipeline do
- context 'when a document only has upload links' do
- it 'does not make any Gitaly calls', :request_store do
- markdown = <<-MARKDOWN.strip_heredoc
- [Relative Upload Link](/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg)
+ subject { described_class.call(doc, context) }
+
+ let_it_be(:project) { create(:project, :public, :repository) }
- ![Relative Upload Image](/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg)
- MARKDOWN
+ let(:context) { { project: project, ref: 'master' } }
- context = {
- project: create(:project, :public, :repository),
- ref: 'master'
- }
+ context 'when a document only has upload links' do
+ let(:doc) do
+ <<-HTML.strip_heredoc
+ <a href="/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg">Relative Upload Link</a>
+ <img src="/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg">
+ HTML
+ end
+ it 'does not make any Gitaly calls', :request_store do
Gitlab::GitalyClient.reset_counts
- described_class.call(markdown, context)
+ subject
expect(Gitlab::GitalyClient.get_request_count).to eq(0)
end
end
+
+ context 'when both upload and repository links are present' do
+ let(:html) do
+ <<-HTML.strip_heredoc
+ <a href="/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg">Relative Upload Link</a>
+ <img src="/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg">
+ <a href="/test.jpg">Just a link</a>
+ HTML
+ end
+
+ let(:doc) { HTML::Pipeline.parse(html) }
+
+ it 'searches for attributes only once' do
+ expect(doc).to receive(:search).once.and_call_original
+
+ subject
+ end
+
+ context 'when "optimize_linkable_attributes" is disabled' do
+ before do
+ stub_feature_flags(optimize_linkable_attributes: false)
+ end
+
+ it 'searches for attributes twice' do
+ expect(doc).to receive(:search).twice.and_call_original
+
+ subject
+ end
+ end
+ end
end
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 32a9f09c3f6..1820141c898 100644
--- a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Banzai::ReferenceParser::MergeRequestParser do
let(:user) { create(: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)) }
+ subject(:parser) { described_class.new(Banzai::RenderContext.new(merge_request.target_project, user)) }
let(:link) { empty_html_link }
@@ -65,4 +65,49 @@ RSpec.describe Banzai::ReferenceParser::MergeRequestParser do
it_behaves_like 'no N+1 queries'
end
+
+ describe '#can_read_reference?' do
+ subject { parser.can_read_reference?(user, merge_request) }
+
+ it { is_expected.to be_truthy }
+
+ context 'when merge request belongs to the private project' do
+ let(:project) { create(:project, :private) }
+
+ it 'prevents user from reading merge request references' do
+ is_expected.to be_falsey
+ end
+
+ context 'when user has access to the project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'with memoization' do
+ context 'when project is the same' do
+ it 'calls #can? only once' do
+ expect(parser).to receive(:can?).once
+
+ 2.times { parser.can_read_reference?(user, merge_request) }
+ end
+ end
+
+ context 'when merge requests belong to different projects' do
+ it 'calls #can? for each project' do
+ expect(parser).to receive(:can?).twice
+
+ another_merge_request = create(:merge_request)
+
+ 2.times do
+ parser.can_read_reference?(user, merge_request)
+ parser.can_read_reference?(user, another_merge_request)
+ end
+ end
+ end
+ end
+ end
end