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::getCallableName private static function Returns a callable as a string suitable for inclusion in a message.
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::setUpBeforeClass public static function

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