e5705f5c54
When cache_collection_render runs we end up reading and writing things to redis even if we already have the rendered field cached in the DB. This commit avoids using redis at all whenever we have the field already rendered in the DB cache.
195 lines
6.4 KiB
Ruby
195 lines
6.4 KiB
Ruby
# Specifications for behavior common to all Mentionable implementations.
|
|
# Requires a shared context containing:
|
|
# - subject { "the mentionable implementation" }
|
|
# - let(:backref_text) { "the way that +subject+ should refer to itself in backreferences " }
|
|
# - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
|
|
|
|
shared_context 'mentionable context' do
|
|
let(:project) { subject.project }
|
|
let(:author) { subject.author }
|
|
|
|
let(:mentioned_issue) { create(:issue, project: project) }
|
|
let!(:mentioned_mr) { create(:merge_request, source_project: project) }
|
|
let(:mentioned_commit) { project.commit("HEAD~1") }
|
|
|
|
let(:ext_proj) { create(:project, :public, :repository) }
|
|
let(:ext_issue) { create(:issue, project: ext_proj) }
|
|
let(:ext_mr) { create(:merge_request, :simple, source_project: ext_proj) }
|
|
let(:ext_commit) { ext_proj.commit("HEAD~2") }
|
|
|
|
# Override to add known commits to the repository stub.
|
|
let(:extra_commits) { [] }
|
|
|
|
# A string that mentions each of the +mentioned_.*+ objects above. Mentionables should add a self-reference
|
|
# to this string and place it in their +mentionable_text+.
|
|
let(:ref_string) do
|
|
<<-MSG.strip_heredoc
|
|
These references are new:
|
|
Issue: #{mentioned_issue.to_reference}
|
|
Merge: #{mentioned_mr.to_reference}
|
|
Commit: #{mentioned_commit.to_reference}
|
|
|
|
This reference is a repeat and should only be mentioned once:
|
|
Repeat: #{mentioned_issue.to_reference}
|
|
|
|
These references are cross-referenced:
|
|
Issue: #{ext_issue.to_reference(project)}
|
|
Merge: #{ext_mr.to_reference(project)}
|
|
Commit: #{ext_commit.to_reference(project)}
|
|
|
|
This is a self-reference and should not be mentioned at all:
|
|
Self: #{backref_text}
|
|
MSG
|
|
end
|
|
|
|
before do
|
|
# Wire the project's repository to return the mentioned commit, and +nil+
|
|
# for any unrecognized commits.
|
|
allow_any_instance_of(::Repository).to receive(:commit).and_call_original
|
|
allow_any_instance_of(::Repository).to receive(:commit).with(mentioned_commit.short_id).and_return(mentioned_commit)
|
|
extra_commits.each do |commit|
|
|
allow_any_instance_of(::Repository).to receive(:commit).with(commit.short_id).and_return(commit)
|
|
end
|
|
|
|
set_mentionable_text.call(ref_string)
|
|
|
|
project.add_developer(author)
|
|
end
|
|
end
|
|
|
|
shared_examples 'a mentionable' do
|
|
include_context 'mentionable context'
|
|
|
|
it 'generates a descriptive back-reference' do
|
|
expect(subject.gfm_reference).to eq(backref_text)
|
|
end
|
|
|
|
it "extracts references from its reference property" do
|
|
# De-duplicate and omit itself
|
|
refs = subject.referenced_mentionables
|
|
expect(refs.size).to eq(6)
|
|
expect(refs).to include(mentioned_issue)
|
|
expect(refs).to include(mentioned_mr)
|
|
expect(refs).to include(mentioned_commit)
|
|
expect(refs).to include(ext_issue)
|
|
expect(refs).to include(ext_mr)
|
|
expect(refs).to include(ext_commit)
|
|
end
|
|
|
|
context 'when there are cached markdown fields' do
|
|
before do
|
|
if subject.is_a?(CacheMarkdownField)
|
|
subject.refresh_markdown_cache
|
|
end
|
|
end
|
|
|
|
it 'sends in cached markdown fields when appropriate' do
|
|
if subject.is_a?(CacheMarkdownField)
|
|
expect_next_instance_of(Gitlab::ReferenceExtractor) do |ext|
|
|
attrs = subject.class.mentionable_attrs.collect(&:first) & subject.cached_markdown_fields.markdown_fields
|
|
attrs.each do |field|
|
|
expect(ext).to receive(:analyze).with(subject.send(field), hash_including(rendered: anything))
|
|
end
|
|
end
|
|
|
|
expect(subject).not_to receive(:refresh_markdown_cache)
|
|
expect(subject).to receive(:cached_markdown_fields).at_least(:once).and_call_original
|
|
|
|
subject.all_references(author)
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'creates cross-reference notes' do
|
|
mentioned_objects = [mentioned_issue, mentioned_mr, mentioned_commit,
|
|
ext_issue, ext_mr, ext_commit]
|
|
|
|
mentioned_objects.each do |referenced|
|
|
expect(SystemNoteService).to receive(:cross_reference)
|
|
.with(referenced, subject.local_reference, author)
|
|
end
|
|
|
|
subject.create_cross_references!
|
|
end
|
|
end
|
|
|
|
shared_examples 'an editable mentionable' do
|
|
include_context 'mentionable context'
|
|
|
|
it_behaves_like 'a mentionable'
|
|
|
|
let(:new_issues) do
|
|
[create(:issue, project: project), create(:issue, project: ext_proj)]
|
|
end
|
|
|
|
context 'when there are cached markdown fields' do
|
|
before do
|
|
if subject.is_a?(CacheMarkdownField)
|
|
subject.refresh_markdown_cache
|
|
end
|
|
end
|
|
|
|
it 'refreshes markdown cache if necessary' do
|
|
subject.save!
|
|
|
|
set_mentionable_text.call('This is a text')
|
|
|
|
if subject.is_a?(CacheMarkdownField)
|
|
expect_next_instance_of(Gitlab::ReferenceExtractor) do |ext|
|
|
subject.cached_markdown_fields.markdown_fields.each do |field|
|
|
expect(ext).to receive(:analyze).with(subject.send(field), hash_including(rendered: anything))
|
|
end
|
|
end
|
|
|
|
expect(subject).to receive(:refresh_markdown_cache)
|
|
expect(subject).to receive(:cached_markdown_fields).at_least(:once).and_call_original
|
|
|
|
subject.all_references(author)
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'creates new cross-reference notes when the mentionable text is edited' do
|
|
subject.save
|
|
subject.create_cross_references!
|
|
|
|
new_text = <<-MSG.strip_heredoc
|
|
These references already existed:
|
|
|
|
Issue: #{mentioned_issue.to_reference}
|
|
|
|
Commit: #{mentioned_commit.to_reference}
|
|
|
|
---
|
|
|
|
This cross-project reference already existed:
|
|
|
|
Issue: #{ext_issue.to_reference(project)}
|
|
|
|
---
|
|
|
|
These two references are introduced in an edit:
|
|
|
|
Issue: #{new_issues[0].to_reference}
|
|
|
|
Cross: #{new_issues[1].to_reference(project)}
|
|
MSG
|
|
|
|
# These three objects were already referenced, and should not receive new
|
|
# notes
|
|
[mentioned_issue, mentioned_commit, ext_issue].each do |oldref|
|
|
expect(SystemNoteService).not_to receive(:cross_reference)
|
|
.with(oldref, any_args)
|
|
end
|
|
|
|
# These two issues are new and should receive reference notes
|
|
# In the case of MergeRequests remember that cannot mention commits included in the MergeRequest
|
|
new_issues.each do |newref|
|
|
expect(SystemNoteService).to receive(:cross_reference)
|
|
.with(newref, subject.local_reference, author)
|
|
end
|
|
|
|
set_mentionable_text.call(new_text)
|
|
subject.create_new_cross_references!(author)
|
|
end
|
|
end
|