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.

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