class EntityCreateAccessCustomCidTest

Tests entity access control handler custom internal cache ID.

@coversDefaultClass \Drupal\Core\Entity\EntityAccessControlHandler

@group Entity

Hierarchy

Expanded class hierarchy of EntityCreateAccessCustomCidTest

File

core/tests/Drupal/Tests/Core/Entity/Access/EntityCreateAccessCustomCidTest.php, line 25

Namespace

Drupal\Tests\Core\Entity\Access
View source
class EntityCreateAccessCustomCidTest extends UnitTestCase {
  
  /**
   * A mock entity type.
   *
   * @var \Drupal\Core\Entity\EntityTypeInterface
   */
  protected EntityTypeInterface $entityType;
  
  /**
   * A mock account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected AccountInterface $account;
  
  /**
   * A language code.
   *
   * @var string
   */
  protected string $langcode;
  
  /**
   * A mock module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected ModuleHandlerInterface $moduleHandler;
  
  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();
    $this->entityType = $this->getMockBuilder(EntityTypeInterface::class)
      ->disableOriginalConstructor()
      ->getMock();
    $this->entityType
      ->expects($this->any())
      ->method('id')
      ->willReturn($this->randomMachineName());
    $this->account = $this->getMockBuilder(AccountInterface::class)
      ->disableOriginalConstructor()
      ->getMock();
    $this->account
      ->expects($this->any())
      ->method('id')
      ->willReturn(rand());
    $language_ids = array_keys(LanguageManager::getStandardLanguageList());
    $this->langcode = $language_ids[array_rand($language_ids)];
    $this->moduleHandler = $this->createMock(ModuleHandlerInterface::class);
    $this->moduleHandler
      ->expects($this->any())
      ->method('invokeAll')
      ->willReturn([]);
  }
  
  /**
   * Setup the access cache on the entity handler for testing.
   *
   * @param \Drupal\Core\Entity\EntityAccessControlHandler $handler
   *   The access control handler.
   * @param bool $in_cache
   *   Whether to prefill the handler's access cache.
   * @param string $cid
   *   The cache ID.
   *
   * @return \ReflectionProperty
   *   A reflection of the handler's accessCache property.
   *
   * @throws \ReflectionException
   */
  protected function setUpAccessCache(EntityAccessControlHandler $handler, bool $in_cache, string $cid) : \ReflectionProperty {
    $access_cache = new \ReflectionProperty($handler, 'accessCache');
    $access_cache->setAccessible(TRUE);
    $cache = [];
    if ($in_cache) {
      // Prefill the handler's internal static cache.
      $cache = [
        $this->account
          ->id() => [
          $cid => [
            $this->langcode => [
              'create' => AccessResult::allowed(),
            ],
          ],
        ],
      ];
    }
    $access_cache->setValue($handler, $cache);
    return $access_cache;
  }
  
  /**
   * Tests the entity access control handler caching with context.
   *
   * @param array $context
   *   The context array for the test createAccess() check.
   * @param bool $in_cache
   *   Whether there is already a cached createAccess() check for the cache ID.
   * @param bool $cacheable
   *   If the test createAccess() check should be cacheable.
   *
   * @covers ::buildCreateAccessCid
   * @dataProvider providerTestDefaultCid
   */
  public function testDefaultCid(array $context, bool $in_cache, bool $cacheable) : void {
    $bundle = $this->randomMachineName();
    $cid = "create:{$bundle}";
    $context['langcode'] = $this->langcode;
    $handler = new EntityAccessControlHandler($this->entityType);
    $handler->setModuleHandler($this->moduleHandler);
    $access_cache = $this->setUpAccessCache($handler, $in_cache, $cid);
    $cache = $access_cache->getValue($handler);
    // The cached value is AccessResult::allowed() but default result is
    // neutral() so createAccess returns TRUE for a cache hit, FALSE otherwise.
    $should_get_from_cache = $in_cache && $cacheable;
    $this->assertSame($should_get_from_cache, $handler->createAccess($bundle, $this->account, $context));
    $should_add_to_cache = $cacheable && !$in_cache;
    $cache_is_changed = $cache !== $access_cache->getValue($handler);
    $this->assertSame($should_add_to_cache, $cache_is_changed);
  }
  
  /**
   * Provides test cases for ::testDefaultCid().
   *
   * @return array[]
   *   A list of test cases.
   */
  public static function providerTestDefaultCid() : array {
    return [
      'no context, cached' => [
        'context' => [],
        'in_cache' => TRUE,
        'cacheable' => TRUE,
      ],
      'no context, uncached' => [
        'context' => [],
        'in_cache' => FALSE,
        'cacheable' => TRUE,
      ],
      'one context var, cached' => [
        'context' => [
          'context_var1' => 'val1',
        ],
        'in_cache' => TRUE,
        'cacheable' => FALSE,
      ],
      'one context var, uncached' => [
        'context' => [
          'context_var1' => 'val1',
        ],
        'in_cache' => FALSE,
        'cacheable' => FALSE,
      ],
      'two context vars, cached' => [
        'context' => [
          'context_var1' => 'val1',
          'context_var2' => 'val2',
        ],
        'in_cache' => TRUE,
        'cacheable' => FALSE,
      ],
      'two context vars, uncached' => [
        'context' => [
          'context_var1' => 'val1',
          'context_var2' => 'val2',
        ],
        'in_cache' => FALSE,
        'cacheable' => FALSE,
      ],
    ];
  }
  
  /**
   * Tests the entity access control handler with a custom static cache ID.
   *
   * @param string $bundle
   *   The machine name of the entity bundle.
   * @param array $context
   *   The context array.
   * @param string $cid
   *   The static cache ID.
   * @param bool $in_cache
   *   Whether there is already a cached createAccess() check for the cache ID.
   *
   * @covers ::buildCreateAccessCid
   * @dataProvider providerTestCustomCid
   */
  public function testCustomCid(string $bundle, array $context, string $cid, bool $in_cache) : void {
    $context['langcode'] = $this->langcode;
    // Drupal\Core\Cache is used when merging access results in
    // checkCreateAccess(), and it calls the cache context manager service.
    $cache_context_manager = $this->createMock(CacheContextsManager::class);
    $cache_context_manager->expects($this->any())
      ->method('assertValidTokens')
      ->willReturn(TRUE);
    $container = new ContainerBuilder();
    \Drupal::setContainer($container);
    $container->set('cache_contexts_manager', $cache_context_manager);
    $handler = new EntityTestAccessControlHandler($this->entityType);
    $handler->setModuleHandler($this->moduleHandler);
    $this->setUpAccessCache($handler, $in_cache, $cid);
    // The prefilled cache is set to AccessResult::allowed(), but the default
    // for EntityTestAccessControlHandler() is neutral(); so createAccess() will
    // return TRUE for a cache hit and FALSE otherwise.
    $this->assertSame($in_cache, $handler->createAccess($bundle, $this->account, $context));
  }
  
  /**
   * Provides test cases for ::testCustomCid().
   *
   * @return array[]
   *   A list of test cases.
   */
  public static function providerTestCustomCid() : array {
    return [
      'no context var, in cache' => [
        'bundle' => 'bundle_1',
        'context' => [],
        'cid' => 'create:bundle_1',
        'in_cache' => TRUE,
      ],
      'no context var, not in cache' => [
        'bundle' => 'bundle_2',
        'context' => [],
        'cid' => 'create:bundle_2',
        'in_cache' => FALSE,
      ],
      'one context var, in cache' => [
        'bundle' => 'bundle_3',
        'context' => [
          'context_var1' => 'val1',
        ],
        'cid' => 'create:bundle_3:val1',
        'in_cache' => TRUE,
      ],
      'one context var, not in cache' => [
        'bundle' => 'bundle_4',
        'context' => [
          'context_var1' => 'val1',
        ],
        'cid' => 'create:bundle_4:val1',
        'in_cache' => FALSE,
      ],
      'two context vars, in cache' => [
        'bundle' => 'bundle_5',
        'context' => [
          'context_var1' => 'val1',
          'context_var2' => 'val2',
        ],
        'cid' => 'create:bundle_5:val1:val2',
        'in_cache' => TRUE,
      ],
      'two context vars, not in cache' => [
        'bundle' => 'bundle_6',
        'context' => [
          'context_var1' => 'val1',
          'context_var2' => 'val2',
        ],
        'cid' => 'create:bundle_6:val1:val2',
        'in_cache' => FALSE,
      ],
    ];
  }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
EntityCreateAccessCustomCidTest::$account protected property A mock account.
EntityCreateAccessCustomCidTest::$entityType protected property A mock entity type.
EntityCreateAccessCustomCidTest::$langcode protected property A language code.
EntityCreateAccessCustomCidTest::$moduleHandler protected property A mock module handler.
EntityCreateAccessCustomCidTest::providerTestCustomCid public static function Provides test cases for ::testCustomCid().
EntityCreateAccessCustomCidTest::providerTestDefaultCid public static function Provides test cases for ::testDefaultCid().
EntityCreateAccessCustomCidTest::setUp protected function Overrides UnitTestCase::setUp
EntityCreateAccessCustomCidTest::setUpAccessCache protected function Setup the access cache on the entity handler for testing.
EntityCreateAccessCustomCidTest::testCustomCid public function Tests the entity access control handler with a custom static cache ID.
EntityCreateAccessCustomCidTest::testDefaultCid public function Tests the entity access control handler caching with context.
ExpectDeprecationTrait::expectDeprecation public function Adds an expected deprecation.
ExpectDeprecationTrait::setUpErrorHandler public function Sets up the test error handler.
ExpectDeprecationTrait::tearDownErrorHandler public function Tears down the test error handler.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
UnitTestCase::$root protected property The app root.
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::setDebugDumpHandler public static function Registers the dumper CLI handler when the DebugDump extension is enabled.
UnitTestCase::setupMockIterator protected function Set up a traversable class mock to return specific items when iterated.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.