95 lines
2.8 KiB
Ruby
95 lines
2.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module AccessMatchersHelpers
|
|
USER_ACCESSOR_METHOD_NAME = 'user'
|
|
|
|
def provide_user(role, membership = nil)
|
|
case role
|
|
when :admin
|
|
create(:admin)
|
|
when :auditor
|
|
create(:user, :auditor)
|
|
when :user
|
|
create(:user)
|
|
when :external
|
|
create(:user, :external)
|
|
when :visitor, :anonymous
|
|
nil
|
|
when User
|
|
role
|
|
when *Gitlab::Access.sym_options_with_owner.keys # owner, maintainer, developer, reporter, guest
|
|
raise ArgumentError, "cannot provide #{role} when membership reference is blank" unless membership
|
|
|
|
provide_user_by_membership(role, membership)
|
|
else
|
|
raise ArgumentError, "cannot provide user of an unknown role #{role}"
|
|
end
|
|
end
|
|
|
|
def provide_user_by_membership(role, membership)
|
|
if role == :owner && membership.owner
|
|
membership.owner
|
|
else
|
|
create(:user).tap do |user|
|
|
membership.public_send(:"add_#{role}", user)
|
|
end
|
|
end
|
|
end
|
|
|
|
def raise_if_non_block_expectation!(actual)
|
|
raise ArgumentError, 'This matcher supports block expectations only.' unless actual.is_a?(Proc)
|
|
end
|
|
|
|
def update_owner(objects, user)
|
|
return unless objects
|
|
|
|
objects.each do |object|
|
|
if object.respond_to?(:owner)
|
|
object.update_attribute(:owner, user)
|
|
elsif object.respond_to?(:user)
|
|
object.update_attribute(:user, user)
|
|
else
|
|
raise ArgumentError, "cannot own this object #{object}"
|
|
end
|
|
end
|
|
end
|
|
|
|
def patch_example_group(user)
|
|
return if user.nil? # for anonymous users
|
|
|
|
# This call is evaluated in context of ExampleGroup instance in which the matcher is called. Overrides the `user`
|
|
# (or defined by `method_name`) method generated by `let` definition in example group before it's used by `subject`.
|
|
# This override is per concrete example only because the example group class gets re-created for each example.
|
|
instance_eval(<<~CODE, __FILE__, __LINE__ + 1)
|
|
if instance_variable_get(:@__#{USER_ACCESSOR_METHOD_NAME}_patched)
|
|
raise ArgumentError, 'An access matcher be_allowed_for/be_denied_for can be used only once per example (`it` block)'
|
|
end
|
|
instance_variable_set(:@__#{USER_ACCESSOR_METHOD_NAME}_patched, true)
|
|
|
|
def #{USER_ACCESSOR_METHOD_NAME}
|
|
@#{USER_ACCESSOR_METHOD_NAME} ||= User.find(#{user.id})
|
|
end
|
|
CODE
|
|
end
|
|
|
|
def prepare_matcher_environment(role, membership, owned_objects)
|
|
user = provide_user(role, membership)
|
|
|
|
if user
|
|
update_owner(owned_objects, user)
|
|
patch_example_group(user)
|
|
end
|
|
end
|
|
|
|
def run_matcher(action, role, membership, owned_objects)
|
|
raise_if_non_block_expectation!(action)
|
|
|
|
prepare_matcher_environment(role, membership, owned_objects)
|
|
|
|
if block_given?
|
|
yield action
|
|
else
|
|
action.call
|
|
end
|
|
end
|
|
end
|