Commit 35015840 authored by Mark Chao's avatar Mark Chao

Merge ApprovableForRule to Approvable

Merge VisibleApprovableForRule to VisibleApprovable
parent 7dc7bfa9
......@@ -7,6 +7,20 @@ module Approvable
# such as approver_groups and target_project in presenters
include ::VisibleApprovable
FORWARDABLE_METHODS = %i{
approval_needed?
approved?
approvals_left
can_approve?
has_approved?
any_approver_allowed?
authors_can_approve?
committers_can_approve?
approvers_overwritten?
}.freeze
delegate(*FORWARDABLE_METHODS, to: :approval_state)
def approval_feature_available?
strong_memoize(:approval_feature_available) do
if project
......@@ -21,30 +35,10 @@ module Approvable
@approval_state ||= ApprovalState.new(self)
end
def approval_needed?
approvals_required&.nonzero?
end
def approved?
approvals_left < 1
end
def approvals_given
approvals.size
end
# Number of approvals remaining (excluding existing approvals) before the MR is
# considered approved. If there are fewer potential approvers than approvals left,
# users should either reduce the number of approvers on projects and/or merge
# requests settings and/or allow MR authors to approve their own merge
# requests (in case only one approval is needed).
#
def approvals_left
approvals_left_count = approvals_required - approvals.size
[approvals_left_count, 0].max
end
def approvals_required
[approvals_before_merge.to_i, target_project.approvals_before_merge.to_i].max
end
......@@ -55,58 +49,6 @@ module Approvable
super
end
# Even though this method is used in VisibleApprovable
# we do not want to encounter a scenario where there are
# no user approvers but there is one merge request group
# approver that is not visible to the current_user,
# which would make this method return false
# when it should still report as overwritten.
# To prevent this from happening, approvers_overwritten?
# makes use of the unfiltered version of approver_groups so that
# it always takes into account every approver
# available
#
def approvers_overwritten?
approvers.to_a.any? || approver_groups.to_a.any?
end
def can_approve?(user)
return false unless user
# The check below considers authors and committers being able to approve the MR.
# That is, they're included/excluded from that list accordingly.
return true if approvers_left.include?(user)
# We can safely unauthorize authors and committers if it reaches this guard clause.
return false if author == user
return false if committers.include?(user)
return false unless user.can?(:update_merge_request, self)
any_approver_allowed? && approvals.where(user: user).empty?
end
def has_approved?(user)
return false unless user
approved_by_users.include?(user)
end
# Once there are fewer approvers left in the list than approvals required or
# there are no more approvals required
# allow other project members to approve the MR.
#
def any_approver_allowed?
remaining_approvals = approvals_left
remaining_approvals.zero? || remaining_approvals > approvers_left.count
end
def authors_can_approve?
target_project.merge_requests_author_approval?
end
def committers_can_approve?
!target_project.merge_requests_disable_committers_approval?
end
def approver_ids=(value)
::Gitlab::Utils.ensure_array_from_string(value).each do |user_id|
next if author && user_id == author.id
......
# frozen_string_literal: true
module ApprovableForRule
include VisibleApprovableForRule
FORWARDABLE_METHODS = %w{
approval_needed?
approved?
approvals_left
can_approve?
has_approved?
any_approver_allowed?
authors_can_approve?
committers_can_approve?
approvers_overwritten?
}.freeze
FORWARDABLE_METHODS.each do |method|
define_method(method) do |*args|
return super(*args) if approval_rules_disabled?
approval_state.public_send(method, *args) # rubocop:disable GitlabSecurity/PublicSend
end
end
end
......@@ -8,9 +8,7 @@ module VisibleApprovable
# Users in the list of approvers who have not already approved this MR.
#
def approvers_left
strong_memoize(:approvers_left) do
User.where(id: all_approvers_including_groups.map(&:id)).where.not(id: approved_by_users.select(:id))
end
approval_state.unactioned_approvers
end
# The list of approvers from either this MR (if they've been set on the MR) or the
......@@ -22,58 +20,21 @@ module VisibleApprovable
#
# @return [Array<User>]
def overall_approvers(exclude_code_owners: false)
code_owners = [] if exclude_code_owners
options = { target: :users }
options[:code_owner] = false if exclude_code_owners
if approvers_overwritten?
code_owners ||= [] # already persisted into database, no need to recompute
approvers_relation = approver_users
else
code_owners ||= self.code_owners.dup
approvers_relation = target_project.approver_users
end
approvers_relation = project.members_among(approvers_relation)
if author && !authors_can_approve?
approvers_relation = approvers_relation.where.not(id: author.id)
end
if committers.any? && !committers_can_approve?
approvers_relation = approvers_relation.where.not(id: committers.select(:id))
end
results = code_owners.concat(approvers_relation)
results.uniq!
results
end
def overall_approver_groups
approvers_overwritten? ? approver_groups : target_project.approver_groups
approvers = approval_state.filtered_approvers(options)
approvers.uniq!
approvers
end
def all_approvers_including_groups
strong_memoize(:all_approvers_including_groups) do
approvers = []
# Approvers not sourced from group level
approvers << overall_approvers
approvers << approvers_from_groups
approvers.flatten
end
approval_state.approvers
end
def approvers_from_groups
group_approvers = overall_approver_groups.flat_map(&:users)
group_approvers.delete(author) unless authors_can_approve?
unless committers_can_approve?
committer_approver_ids = committers.where(id: group_approvers.map(&:id)).pluck(:id)
group_approvers.reject! { |user| committer_approver_ids.include?(user.id) }
end
group_approvers
groups = approval_state.wrapped_approval_rules.flat_map(&:groups)
User.joins(:group_members).where(members: { source_id: groups })
end
def reset_approval_cache!
......
# frozen_string_literal: true
# This module may only be used by presenters or modules
# that include the Approvable concern
module VisibleApprovableForRule
def approvers_left
return super if approval_rules_disabled?
approval_state.unactioned_approvers
end
def overall_approvers(exclude_code_owners: false)
return super if approval_rules_disabled?
options = { target: :users }
options[:code_owner] = false if exclude_code_owners
approvers = approval_state.filtered_approvers(options)
approvers.uniq!
approvers
end
def all_approvers_including_groups
return super if approval_rules_disabled?
approval_state.approvers
end
def approvers_from_groups
return super if approval_rules_disabled?
groups = approval_state.wrapped_approval_rules.flat_map(&:groups)
User.joins(:group_members).where(members: { source_id: groups })
end
def approval_rules_disabled?
::Feature.disabled?(:approval_rules, project, default_enabled: true)
end
end
......@@ -8,7 +8,6 @@ module EE
include ::Approvable
include ::Gitlab::Utils::StrongMemoize
include FromUnion
prepend ApprovableForRule
prepended do
include Elastic::MergeRequestsSearch
......
......@@ -3,7 +3,6 @@
module EE
module MergeRequestPresenter
include ::VisibleApprovable
prepend VisibleApprovableForRule
def approvals_path
if expose_mr_approval_path?
......
......@@ -9,7 +9,6 @@ shared_examples 'approvals' do
let!(:approval_rule) { create(:approval_project_rule, project: project, users: [approver, user], approvals_required: 2) }
before do
# merge_request.update_attribute :approvals_before_merge, 2
project.add_developer(approver)
end
......
# frozen_string_literal: true
require 'spec_helper'
# Based on approvable_spec.rb
describe ApprovableForRule do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:author) { merge_request.author }
describe '#approvers_overwritten?' do
subject { merge_request.approvers_overwritten? }
it 'returns false when merge request has no approvers' do
is_expected.to be false
end
it 'returns true when merge request has user approver' do
create(:approver, target: merge_request)
is_expected.to be true
end
it 'returns true when merge request has group approver' do
group = create(:group_with_members)
create(:approver_group, target: merge_request, group: group)
is_expected.to be true
end
end
describe '#can_approve?' do
subject { merge_request.can_approve?(user) }
it 'returns false if user is nil' do
expect(merge_request.can_approve?(nil)).to be false
end
it 'returns true when user is included in the approvers list' do
user = create(:approver, target: merge_request).user
expect(merge_request.can_approve?(user)).to be true
end
context 'when the user is the author' do
context 'and author is an approver' do
before do
create(:approver, target: merge_request, user: author)
end
it 'returns true when authors can approve' do
project.update!(merge_requests_author_approval: true)
expect(merge_request.can_approve?(author)).to be true
end
it 'returns false when authors cannot approve' do
project.update!(merge_requests_author_approval: false)
expect(merge_request.can_approve?(author)).to be false
end
end
context 'and author is not an approver' do
it 'returns true when authors can approve' do
project.update!(merge_requests_author_approval: true)
expect(merge_request.can_approve?(author)).to be true
end
it 'returns false when authors cannot approve' do
project.update!(merge_requests_author_approval: false)
expect(merge_request.can_approve?(author)).to be false
end
end
end
context 'when user is a committer' do
let(:user) { create(:user, email: merge_request.commits.without_merge_commits.first.committer_email) }
before do
project.add_developer(user)
end
context 'and committer is an approver' do
before do
create(:approver, target: merge_request, user: user)
end
it 'return true when committers can approve' do
project.update!(merge_requests_disable_committers_approval: false)
expect(merge_request.can_approve?(user)).to be true
end
it 'return false when committers cannot approve' do
project.update!(merge_requests_disable_committers_approval: true)
expect(merge_request.can_approve?(user)).to be false
end
end
context 'and committer is not an approver' do
it 'return true when committers can approve' do
project.update!(merge_requests_disable_committers_approval: false)
expect(merge_request.can_approve?(user)).to be true
end
it 'return false when committers cannot approve' do
project.update!(merge_requests_disable_committers_approval: true)
expect(merge_request.can_approve?(user)).to be false
end
end
end
it 'returns false when user is unable to update the merge request' do
user = create(:user)
project.add_guest(user)
expect(merge_request.can_approve?(user)).to be false
end
context 'when approvals are required' do
before do
project.update!(approvals_before_merge: 1)
end
it 'returns true when approvals are still accepted and user still has not approved' do
user = create(:user)
project.add_developer(user)
expect(merge_request.can_approve?(user)).to be true
end
it 'returns false when there is still one approver missing' do
user = create(:user)
project.add_developer(user)
create(:approver, target: merge_request)
expect(merge_request.can_approve?(user)).to be false
end
end
end
end
require 'spec_helper'
describe Approvable do
let(:merge_request) { create(:merge_request) }
subject(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:author) { merge_request.author }
before do
stub_feature_flags(approval_rules: false)
end
describe '#approval_feature_available?' do
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
......@@ -27,140 +23,7 @@ describe Approvable do
end
end
describe '#approvers_overwritten?' do
subject { merge_request.approvers_overwritten? }
it 'returns false when merge request has no approvers' do
is_expected.to be false
end
it 'returns true when merge request has user approver' do
create(:approver, target: merge_request)
is_expected.to be true
end
it 'returns true when merge request has group approver' do
group = create(:group_with_members)
create(:approver_group, target: merge_request, group: group)
is_expected.to be true
end
end
describe '#can_approve?' do
subject { merge_request.can_approve?(user) }
it 'returns false if user is nil' do
expect(merge_request.can_approve?(nil)).to be false
end
it 'returns true when user is included in the approvers list' do
user = create(:approver, target: merge_request).user
expect(merge_request.can_approve?(user)).to be true
end
context 'when authors can approve' do
before do
project.update(merge_requests_author_approval: true)
end
context 'when the user is the author' do
it 'returns true when user is approver' do
create(:approver, target: merge_request, user: author)
expect(merge_request.can_approve?(author)).to be true
end
it 'returns false when user is not approver' do
expect(merge_request.can_approve?(author)).to be false
end
end
context 'when user is committer' do
let(:user) { create(:user, email: merge_request.commits.without_merge_commits.first.committer_email) }
before do
project.add_developer(user)
end
context 'and committers can not approve' do
before do
project.update(merge_requests_disable_committers_approval: true)
end
it 'returns true when user is approver' do
create(:approver, target: merge_request, user: user)
expect(merge_request.can_approve?(user)).to be false
end
it 'returns false when user is not approver' do
expect(merge_request.can_approve?(user)).to be false
end
end
context 'and committers can approve' do
it 'returns true when user is approver' do
create(:approver, target: merge_request, user: user)
expect(merge_request.can_approve?(user)).to be true
end
it 'returns false when user is not approver' do
expect(merge_request.can_approve?(user)).to be false
end
end
end
end
context 'when authors cannot approve' do
before do
project.update(merge_requests_author_approval: false)
end
it 'returns false when user is the author' do
create(:approver, target: merge_request, user: author)
expect(merge_request.can_approve?(author)).to be false
end
it 'returns true when user is a committer' do
user = create(:user, email: merge_request.commits.without_merge_commits.first.committer_email)
project.add_developer(user)
create(:approver, target: merge_request, user: user)
expect(merge_request.can_approve?(user)).to be true
end
end
it 'returns false when user is unable to update the merge request' do
user = create(:user)
project.add_guest(user)
expect(merge_request.can_approve?(user)).to be false
end
context 'when approvals are required' do
before do
project.update(approvals_before_merge: 1)
end
it 'returns true when approvals are still accepted and user still has not approved' do
user = create(:user)
project.add_developer(user)
expect(merge_request.can_approve?(user)).to be true
end
it 'returns false when there is still one approver missing' do
user = create(:user)
project.add_developer(user)
create(:approver, target: merge_request)
expect(merge_request.can_approve?(user)).to be false
end
end
described_class::FORWARDABLE_METHODS.each do |method|
it { is_expected.to delegate_method(method).to(:approval_state) }
end
end
......@@ -1174,8 +1174,83 @@ describe ApprovalState do
let(:developer) { create_project_member(:developer) }
let(:other_developer) { create_project_member(:developer) }
let(:reporter) { create_project_member(:reporter) }
let(:guest) { create_project_member(:guest) }
let(:stranger) { create(:user) }
context 'when the user is the author' do
context 'and author is an approver' do
before do
create(:approval_project_rule, project: project, users: [author])
end
it 'returns true when authors can approve' do
project.update!(merge_requests_author_approval: true)
expect(subject.can_approve?(author)).to be true
end
it 'returns false when authors cannot approve' do
project.update!(merge_requests_author_approval: false)
expect(subject.can_approve?(author)).to be false
end
end
context 'and author is not an approver' do
it 'returns true when authors can approve' do
project.update!(merge_requests_author_approval: true)
expect(subject.can_approve?(author)).to be true
end
it 'returns false when authors cannot approve' do
project.update!(merge_requests_author_approval: false)
expect(subject.can_approve?(author)).to be false
end
end
end
context 'when user is a committer' do
let(:user) { create(:user, email: merge_request.commits.without_merge_commits.first.committer_email) }
before do
project.add_developer(user)
end
context 'and committer is an approver' do
before do
create(:approval_project_rule, project: project, users: [user])
end
it 'return true when committers can approve' do
project.update!(merge_requests_disable_committers_approval: false)
expect(subject.can_approve?(user)).to be true
end
it 'return false when committers cannot approve' do
project.update!(merge_requests_disable_committers_approval: true)
expect(subject.can_approve?(user)).to be false
end
end
context 'and committer is not an approver' do
it 'return true when committers can approve' do
project.update!(merge_requests_disable_committers_approval: false)
expect(subject.can_approve?(user)).to be true
end
it 'return false when committers cannot approve' do
project.update!(merge_requests_disable_committers_approval: true)
expect(subject.can_approve?(user)).to be false
end
end
end
context 'when there is one approver required' do
let!(:rule) { create_rule(approvals_required: 1) }
......@@ -1318,6 +1393,7 @@ describe ApprovalState do
expect(subject.can_approve?(author)).to be_falsey
expect(subject.can_approve?(reporter)).to be_falsey
expect(subject.can_approve?(guest)).to be_falsey
expect(subject.can_approve?(stranger)).to be_falsey
expect(subject.can_approve?(nil)).to be_falsey
end
......@@ -1347,6 +1423,7 @@ describe ApprovalState do
expect(subject.can_approve?(author)).to be_falsey
expect(subject.can_approve?(reporter)).to be_falsey
expect(subject.can_approve?(other_developer)).to be_truthy
expect(subject.can_approve?(guest)).to be_falsey
expect(subject.can_approve?(stranger)).to be_falsey
expect(subject.can_approve?(nil)).to be_falsey
end
......
# frozen_string_literal: true
require 'spec_helper'
# Based on visible_approvable_spec.rb
describe VisibleApprovableForRule do
let(:resource) { create(:merge_request, source_project: project, target_project: project) }
let!(:project) { create(:project, :repository) }
let!(:user) { project.creator }
describe '#approvers_left' do
let!(:private_group) { create(:group_with_members, :private) }
let!(:public_group) { create(:group_with_members) }
let!(:public_approver_group) { create(:approver_group, target: resource, group: public_group) }
let!(:private_approver_group) { create(:approver_group, target: resource, group: private_group) }
let!(:approver) { create(:approver, target: resource) }
subject { resource.approvers_left }
it 'avoids N+1 queries' do
control = ActiveRecord::QueryRecorder.new { subject }
expect { subject }.not_to exceed_query_limit(control)
end
it 'returns all approvers left' do
resource.approvals.create!(user: approver.user)
is_expected.to match_array(public_approver_group.users + private_approver_group.users)
end
end
describe '#overall_approvers' do
let(:approver) { create(:user) }
let(:code_owner) { build(:user) }
let!(:project_regular_rule) { create(:approval_project_rule, project: project, users: [approver]) }
let!(:code_owner_rule) { create(:code_owner_rule, merge_request: resource, users: [code_owner]) }
before do
project.add_developer(approver)
project.add_developer(code_owner)
end
subject { resource.overall_approvers }
it 'returns a list of all the project approvers' do
is_expected.to contain_exactly(approver, code_owner)
end
context 'when exclude_code_owners is true' do
subject { resource.overall_approvers(exclude_code_owners: true) }
it 'excludes code owners' do
is_expected.to contain_exactly(approver)
end
end
context 'when approvers are overwritten' do
let!(:merge_request_regular_rule) { create(:approval_merge_request_rule, merge_request: resource, users: [create(:user)]) }
it 'returns the list of all the merge request level approvers' do
is_expected.to contain_exactly(*merge_request_regular_rule.users, code_owner)
end
end
context 'when author is an approver' do
let!(:approver) { resource.author }
it 'excludes author if author cannot approve' do
project.update(merge_requests_author_approval: false)
is_expected.not_to include(approver)
end
it 'includes author if author is able to approve' do
project.update(merge_requests_author_approval: true)
is_expected.to include(approver)
end
end
context 'when a committer is an approver' do
let!(:approver) { create(:user, email: resource.commits.without_merge_commits.first.committer_email) }
it 'excludes the committer if committers cannot approve' do
project.update(merge_requests_disable_committers_approval: true)
is_expected.not_to include(approver)
end
it 'includes the committer if committers are able to approve' do
project.update(merge_requests_disable_committers_approval: false)
is_expected.to include(approver)
end
end
end
describe '#all_approvers_including_groups' do
let!(:group) { create(:group_with_members) }
let!(:approver_group) { create(:approver_group, target: resource, group: group) }
let!(:approver) { create(:approver, target: resource) }
subject { resource.all_approvers_including_groups }
it 'returns all approvers (groups and users)' do
is_expected.to match_array(approver_group.users + [approver.user])
end
end
describe '#authors_can_approve?' do
subject { resource.authors_can_approve? }
it 'returns false when merge_requests_author_approval flag is off' do
is_expected.to be false
end
it 'returns true when merge_requests_author_approval flag is turned on' do
project.update(merge_requests_author_approval: true)
is_expected.to be true
end
end
end
......@@ -5,16 +5,15 @@ describe VisibleApprovable do
let!(:project) { create(:project, :repository) }
let!(:user) { project.creator }
before do
stub_feature_flags(approval_rules: false)
end
describe '#approvers_left' do
let!(:private_group) { create(:group_with_members, :private) }
let!(:public_group) { create(:group_with_members) }
let!(:public_approver_group) { create(:approver_group, target: resource, group: public_group) }
let!(:private_approver_group) { create(:approver_group, target: resource, group: private_group) }
let!(:approver) { create(:approver, target: resource) }
let!(:approver) { create(:user) }
let!(:rule) { create(:approval_project_rule, project: project, groups: [public_group, private_group], users: [approver])}
before do
project.add_developer(approver)
end
subject { resource.approvers_left }
......@@ -25,130 +24,88 @@ describe VisibleApprovable do
end
it 'returns all approvers left' do
resource.approvals.create!(user: approver.user)
resource.approvals.create!(user: approver)
is_expected.to match_array(public_approver_group.users + private_approver_group.users)
is_expected.to match_array(public_group.users + private_group.users)
end
end
describe '#overall_approvers' do
let!(:project_approver) { create(:approver, target: project) }
let(:approver) { create(:user) }
let(:code_owner) { build(:user) }
let!(:project_regular_rule) { create(:approval_project_rule, project: project, users: [approver]) }
let!(:code_owner_rule) { create(:code_owner_rule, merge_request: resource, users: [code_owner]) }
before do
allow(resource).to receive(:code_owners).and_return([code_owner])
project.add_developer(project_approver.user)
project.add_developer(approver)
project.add_developer(code_owner)
end
subject { resource.overall_approvers }
it 'returns a list of all the project approvers' do
is_expected.to contain_exactly(project_approver.user, code_owner)
is_expected.to contain_exactly(approver, code_owner)
end
context 'when exclude_code_owners is true' do
subject { resource.overall_approvers(exclude_code_owners: true) }
it 'excludes code owners' do
is_expected.to contain_exactly(project_approver.user)
is_expected.to contain_exactly(approver)
end
end
context 'when author is approver' do
let!(:author_approver) { create(:approver, target: project, user: resource.author) }
it 'excludes author if authors cannot approve' do
is_expected.not_to include(author_approver.user)
end
it 'includes author if authors are able to approve' do
project.update(merge_requests_author_approval: true)
is_expected.to include(author_approver.user)
end
end
context 'when committer is approver' do
let(:user) { create(:user, email: resource.commits.without_merge_commits.first.committer_email) }
let!(:committer_approver) { create(:approver, target: project, user: user) }
before do
project.add_developer(user)
end
it 'excludes committer if committers cannot approve' do
project.update(merge_requests_disable_committers_approval: true)
is_expected.not_to include(committer_approver.user)
end
context 'when approvers are overwritten' do
let!(:merge_request_regular_rule) { create(:approval_merge_request_rule, merge_request: resource, users: [create(:user)]) }
it 'includes committer if committers are able to approve' do
is_expected.to include(committer_approver.user)
it 'returns the list of all the merge request level approvers' do
is_expected.to contain_exactly(*merge_request_regular_rule.users, code_owner)
end
end
context 'when approvers are overwritten' do
let!(:approver) { create(:approver, target: resource) }
context 'when author is an approver' do
let!(:approver) { resource.author }
before do
project.add_developer(approver.user)
end
it 'excludes author if author cannot approve' do
project.update(merge_requests_author_approval: false)
it 'returns the list of all the merge request user approvers' do
is_expected.to contain_exactly(approver.user)
is_expected.not_to include(approver)
end
end
context 'when approver is no longer part of project' do
it 'excludes non-project members' do
project.team.find_member(project_approver.user).destroy!
it 'includes author if author is able to approve' do
project.update(merge_requests_author_approval: true)
is_expected.not_to include(project_approver.user)
is_expected.to include(approver)
end
end
end
describe '#overall_approver_groups' do
before do
group = create(:group_with_members)
create(:approver_group, target: project, group: group)
end
context 'when a committer is an approver' do
let!(:approver) { create(:user, email: resource.commits.without_merge_commits.first.committer_email) }
subject { resource.overall_approver_groups }
it 'excludes the committer if committers cannot approve' do
project.update(merge_requests_disable_committers_approval: true)
it 'returns all the project approver groups' do
is_expected.to match_array(project.approver_groups)
end
is_expected.not_to include(approver)
end
context 'when group approvers are overwritten' do
it 'returns all the merge request approver groups' do
group = create(:group_with_members)
create(:approver_group, target: resource, group: group)
it 'includes the committer if committers are able to approve' do
project.update(merge_requests_disable_committers_approval: false)
is_expected.to match_array(resource.approver_groups)
is_expected.to include(approver)
end
end
end
describe '#all_approvers_including_groups' do
let!(:group) { create(:group_with_members) }
let!(:approver_group) { create(:approver_group, target: resource, group: group) }
let!(:approver) { create(:approver, target: resource) }
before do
project.add_developer(approver.user)
end
let!(:approver) { create(:user) }
let!(:rule) { create(:approval_project_rule, project: project, groups: [group], users: [approver]) }
subject { resource.all_approvers_including_groups }
it 'only queries once' do
expect(resource).to receive(:overall_approvers).and_call_original.once
3.times { subject }
end
it 'returns all approvers (groups and users)' do
is_expected.to match_array(approver_group.users + [approver.user])
is_expected.to match_array(group.users + [approver])
end
end
......@@ -168,8 +125,9 @@ describe VisibleApprovable do
describe '#reset_approval_cache!' do
before do
approver = create(:approver, target: resource)
project.add_developer(approver.user)
approver = create(:user)
project.add_developer(approver)
create(:approval_project_rule, project: project, users: [approver])
end
subject { resource.reset_approval_cache! }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment