gitlab-org--gitlab-foss/spec/requests/api/discussions_spec.rb
Stan Hu e24b9c2502 Eliminate Gitaly N+1 queries with notes API
Similar to https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/31834,
we see that in https://gitlab.com/gitlab-org/gitlab-ce/issues/65957
there can be hundreds, even thousands, of Gitaly requests in the
`/api/:version/projects/:id/merge_requests/:noteable_id/notes` endpoint.

Previously, the API to retrieve notes generated hundreds of Gitaly calls
to determine whether a system note should be shown to the user. It did
this by:

1. Rendering the Markdown
2. Extracting cross-references from the Markdown
3. Issuing a Gitaly `FindCommit` RPC for every reference to validate
that the commit exists.

The last step is unnecessary because we don't need to display a commit
if the user doesn't have access to the project in the first place.
`RendersNotes#prepare_notes_for_rendering` is already used in
`MergeRequestsController`, which is why we don't see N+1 Gitaly calls
there. We use it here to optimize the note redaction process.
2019-08-22 22:28:47 -07:00

61 lines
2.6 KiB
Ruby

require 'spec_helper'
describe API::Discussions do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, :repository, namespace: user.namespace) }
let(:private_user) { create(:user) }
before do
project.add_developer(user)
end
context 'when discussions have cross-reference system notes' do
let(:url) { "/projects/#{project.id}/merge_requests/#{merge_request.iid}/discussions" }
let(:notes_in_response) { json_response.first['notes'] }
it_behaves_like 'with cross-reference system notes'
end
context 'when noteable is an Issue' do
let!(:issue) { create(:issue, project: project, author: user) }
let!(:issue_note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: user) }
it_behaves_like 'discussions API', 'projects', 'issues', 'iid', can_reply_to_individual_notes: true do
let(:parent) { project }
let(:noteable) { issue }
let(:note) { issue_note }
end
end
context 'when noteable is a Snippet' do
let!(:snippet) { create(:project_snippet, project: project, author: user) }
let!(:snippet_note) { create(:discussion_note_on_snippet, noteable: snippet, project: project, author: user) }
it_behaves_like 'discussions API', 'projects', 'snippets', 'id' do
let(:parent) { project }
let(:noteable) { snippet }
let(:note) { snippet_note }
end
end
context 'when noteable is a Merge Request' do
let!(:noteable) { create(:merge_request_with_diffs, source_project: project, target_project: project, author: user) }
let!(:note) { create(:discussion_note_on_merge_request, noteable: noteable, project: project, author: user) }
let!(:diff_note) { create(:diff_note_on_merge_request, noteable: noteable, project: project, author: user) }
let(:parent) { project }
it_behaves_like 'discussions API', 'projects', 'merge_requests', 'iid', can_reply_to_individual_notes: true
it_behaves_like 'diff discussions API', 'projects', 'merge_requests', 'iid'
it_behaves_like 'resolvable discussions API', 'projects', 'merge_requests', 'iid'
end
context 'when noteable is a Commit' do
let!(:noteable) { create(:commit, project: project, author: user) }
let!(:note) { create(:discussion_note_on_commit, commit_id: noteable.id, project: project, author: user) }
let!(:diff_note) { create(:diff_note_on_commit, commit_id: noteable.id, project: project, author: user) }
let(:parent) { project }
it_behaves_like 'discussions API', 'projects', 'repository/commits', 'id'
it_behaves_like 'diff discussions API', 'projects', 'repository/commits', 'id'
end
end