102 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Ruby
		
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
module AccessMatchersHelpers
 | 
						|
  include Gitlab::Utils::StrongMemoize
 | 
						|
 | 
						|
  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)
 | 
						|
      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 reset_matcher_environment
 | 
						|
    instance_eval(<<~CODE, __FILE__, __LINE__ + 1)
 | 
						|
      clear_memoization(:#{USER_ACCESSOR_METHOD_NAME})
 | 
						|
      undef #{USER_ACCESSOR_METHOD_NAME} if defined? user
 | 
						|
    CODE
 | 
						|
  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
 | 
						|
 | 
						|
    reset_matcher_environment
 | 
						|
  end
 | 
						|
end
 |