gitlab-org--gitlab-foss/spec/models/issue_spec.rb
Alejandro Rodríguez ea63346df5 Refactor user authorization check for a single project to avoid querying all user projects
Currently, even when searching for all authorized issues of *one* project, we run the
`Users#authorized_projects` query (which can be rather slow). This update checks if
we are handling issues of just one project and does the authorization check locally.
It does have the downside of basically repeating the logic of `Users#authorized_projects`
on `Project#authorized_for_user`.
2016-07-20 15:14:31 -04:00

309 lines
9.5 KiB
Ruby

require 'spec_helper'
describe Issue, models: true do
describe "Associations" do
it { is_expected.to belong_to(:milestone) }
end
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(InternalId) }
it { is_expected.to include_module(Issuable) }
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Sortable) }
it { is_expected.to include_module(Taskable) }
end
subject { create(:issue) }
describe "act_as_paranoid" do
it { is_expected.to have_db_column(:deleted_at) }
it { is_expected.to have_db_index(:deleted_at) }
end
describe 'visible_to_user' do
let(:user) { create(:user) }
let(:authorized_user) { create(:user) }
let(:project) { create(:project, namespace: authorized_user.namespace) }
let!(:public_issue) { create(:issue, project: project) }
let!(:confidential_issue) { create(:issue, project: project, confidential: true) }
it 'returns non confidential issues for nil user' do
expect(Issue.visible_to_user(nil).count).to be(1)
end
it 'returns non confidential issues for user not authorized for the issues projects' do
expect(Issue.visible_to_user(user).count).to be(1)
end
it 'returns all issues for user authorized for the issues projects' do
expect(Issue.visible_to_user(authorized_user).count).to be(2)
end
end
describe '#to_reference' do
it 'returns a String reference to the object' do
expect(subject.to_reference).to eq "##{subject.iid}"
end
it 'supports a cross-project reference' do
cross = double('project')
expect(subject.to_reference(cross)).
to eq "#{subject.project.to_reference}##{subject.iid}"
end
end
describe '#is_being_reassigned?' do
it 'returns true if the issue assignee has changed' do
subject.assignee = create(:user)
expect(subject.is_being_reassigned?).to be_truthy
end
it 'returns false if the issue assignee has not changed' do
expect(subject.is_being_reassigned?).to be_falsey
end
end
describe '#is_being_reassigned?' do
it 'returns issues assigned to user' do
user = create(:user)
create_list(:issue, 2, assignee: user)
expect(Issue.open_for(user).count).to eq 2
end
end
describe '#closed_by_merge_requests' do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project, state: "opened")}
let(:closed_issue) { build(:issue, project: project, state: "closed")}
let(:mr) do
opts = {
title: 'Awesome merge_request',
description: "Fixes #{issue.to_reference}",
source_branch: 'feature',
target_branch: 'master'
}
MergeRequests::CreateService.new(project, project.owner, opts).execute
end
let(:closed_mr) do
opts = {
title: 'Awesome merge_request 2',
description: "Fixes #{issue.to_reference}",
source_branch: 'feature',
target_branch: 'master',
state: 'closed'
}
MergeRequests::CreateService.new(project, project.owner, opts).execute
end
it 'returns the merge request to close this issue' do
allow(mr).to receive(:closes_issue?).with(issue).and_return(true)
expect(issue.closed_by_merge_requests).to eq([mr])
end
it "returns an empty array when the current issue is closed already" do
expect(closed_issue.closed_by_merge_requests).to eq([])
end
end
describe '#referenced_merge_requests' do
it 'returns the referenced merge requests' do
project = create(:project, :public)
mr1 = create(:merge_request,
source_project: project,
source_branch: 'master',
target_branch: 'feature')
mr2 = create(:merge_request,
source_project: project,
source_branch: 'feature',
target_branch: 'master')
issue = create(:issue, description: mr1.to_reference, project: project)
create(:note_on_issue,
noteable: issue,
note: mr2.to_reference,
project_id: project.id)
expect(issue.referenced_merge_requests).to eq([mr1, mr2])
end
end
describe '#can_move?' do
let(:user) { create(:user) }
let(:issue) { create(:issue) }
subject { issue.can_move?(user) }
context 'user is not a member of project issue belongs to' do
it { is_expected.to eq false}
end
context 'user is reporter in project issue belongs to' do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
before { project.team << [user, :reporter] }
it { is_expected.to eq true }
context 'issue not persisted' do
let(:issue) { build(:issue, project: project) }
it { is_expected.to eq false }
end
context 'checking destination project also' do
subject { issue.can_move?(user, to_project) }
let(:to_project) { create(:project) }
context 'destination project allowed' do
before { to_project.team << [user, :reporter] }
it { is_expected.to eq true }
end
context 'destination project not allowed' do
before { to_project.team << [user, :guest] }
it { is_expected.to eq false }
end
end
end
end
describe '#moved?' do
let(:issue) { create(:issue) }
subject { issue.moved? }
context 'issue not moved' do
it { is_expected.to eq false }
end
context 'issue already moved' do
let(:moved_to_issue) { create(:issue) }
let(:issue) { create(:issue, moved_to: moved_to_issue) }
it { is_expected.to eq true }
end
end
describe '#related_branches' do
let(:user) { build(:admin) }
before do
allow(subject.project.repository).to receive(:branch_names).
and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name, "#{subject.iid}-branch"])
# Without this stub, the `create(:merge_request)` above fails because it can't find
# the source branch. This seems like a reasonable compromise, in comparison with
# setting up a full repo here.
allow_any_instance_of(MergeRequest).to receive(:create_merge_request_diff)
end
it "selects the right branches when there are no referenced merge requests" do
expect(subject.related_branches(user)).to eq([subject.to_branch_name, "#{subject.iid}-branch"])
end
it "selects the right branches when there is a referenced merge request" do
merge_request = create(:merge_request, { description: "Closes ##{subject.iid}",
source_project: subject.project,
source_branch: "#{subject.iid}-branch" })
merge_request.create_cross_references!(user)
expect(subject.referenced_merge_requests).not_to be_empty
expect(subject.related_branches(user)).to eq([subject.to_branch_name])
end
it 'excludes stable branches from the related branches' do
allow(subject.project.repository).to receive(:branch_names).
and_return(["#{subject.iid}-0-stable"])
expect(subject.related_branches(user)).to eq []
end
end
it_behaves_like 'an editable mentionable' do
subject { create(:issue) }
let(:backref_text) { "issue #{subject.to_reference}" }
let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
end
it_behaves_like 'a Taskable' do
let(:subject) { create :issue }
end
describe "#to_branch_name" do
let(:issue) { create(:issue, title: 'testing-issue') }
it 'starts with the issue iid' do
expect(issue.to_branch_name).to match /\A#{issue.iid}-[A-Za-z\-]+\z/
end
it "contains the issue title if not confidential" do
expect(issue.to_branch_name).to match /testing-issue\z/
end
it "does not contain the issue title if confidential" do
issue = create(:issue, title: 'testing-issue', confidential: true)
expect(issue.to_branch_name).to match /confidential-issue\z/
end
end
describe '#participants' do
context 'using a public project' do
let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) }
let!(:note1) do
create(:note_on_issue, noteable: issue, project: project, note: 'a')
end
let!(:note2) do
create(:note_on_issue, noteable: issue, project: project, note: 'b')
end
it 'includes the issue author' do
expect(issue.participants).to include(issue.author)
end
it 'includes the authors of the notes' do
expect(issue.participants).to include(note1.author, note2.author)
end
end
context 'using a private project' do
it 'does not include mentioned users that do not have access to the project' do
project = create(:project)
user = create(:user)
issue = create(:issue, project: project)
create(:note_on_issue,
noteable: issue,
project: project,
note: user.to_reference)
expect(issue.participants).not_to include(user)
end
end
end
describe 'cached counts' do
it 'updates when assignees change' do
user1 = create(:user)
user2 = create(:user)
issue = create(:issue, assignee: user1)
expect(user1.assigned_open_issues_count).to eq(1)
expect(user2.assigned_open_issues_count).to eq(0)
issue.assignee = user2
issue.save
expect(user1.assigned_open_issues_count).to eq(0)
expect(user2.assigned_open_issues_count).to eq(1)
end
end
end