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
 |