clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
<?php
namespace Drupal\Tests\entity\Functional;
use Drupal\entity_module_test\Entity\EnhancedEntityWithOwner;
use Drupal\Tests\block\Traits\BlockCreationTrait;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the bulk-form list builder.
*
* @group entity
*
* @runTestsInSeparateProcesses
*
* @preserveGlobalState disabled
*/
class BulkFormEntityListBuilderTest extends BrowserTestBase {
use BlockCreationTrait;
/**
* The entity storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected static $modules = ['entity_module_test', 'user', 'entity', 'block'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* The base permissions to grant for the test user.
*
* @var string[]
*/
protected $basePermissions = [
'access entity_test_enhanced_with_owner overview',
'view any entity_test_enhanced_with_owner',
'view own unpublished entity_test_enhanced_with_owner',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
/* @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
$entity_type_manager = $this->container->get('entity_type.manager');
$this->storage = $entity_type_manager->getStorage('entity_test_enhanced_with_owner');
$this->placeBlock('page_title_block');
$this->placeBlock('local_tasks_block');
$account = $this->drupalCreateUser($this->basePermissions);
$this->drupalLogin($account);
}
/**
* Tests that the bulk form is displayed correctly.
*/
public function testBulkForm() {
$entity = $this->storage->create([
'name' => 'Entity 1',
'type' => 'default',
]);
$collection_url = $entity->getEntityType()->getLinkTemplate('collection');
// Without any entities the bulk form should not be shown.
$this->drupalGet($collection_url);
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->fieldNotExists('Action');
$this->assertSession()->buttonNotExists('Apply to selected items');
// Create an entity and make sure that the bulk form is shown.
$entity->save();
$this->drupalGet($collection_url);
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->fieldExists('Action');
$this->assertSession()->buttonExists('Apply to selected items');
$this->submitForm([], 'Apply to selected items');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Error message"]', 'No items selected.');
}
/**
* Test the delete action on the bulk form.
*/
public function testDeleteAction() {
$entity = $this->storage->create([
'name' => 'Entity 1',
'type' => 'default',
'user_id' => $this->loggedInUser->id(),
]);
$entity->save();
$id = $entity->id();
$this->drupalGet($entity->toUrl('collection'));
$this->assertSession()->fieldValueEquals('Action', 'entity_test_enhanced_with_owner_delete_action');
$edit = ["entities[$id]" => $id];
$this->submitForm($edit, 'Apply to selected items');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Error message"]', 'No access to execute Delete enhanced entities with owner on the enhanced entity with owner Entity 1.');
$this->assertInstanceOf(EnhancedEntityWithOwner::class, $this->storage->load($id));
$account = $this->drupalCreateUser(array_merge(
$this->basePermissions,
['delete any default entity_test_enhanced_with_owner']
));
$this->drupalLogin($account);
$this->drupalGet($entity->toUrl('collection'));
$this->submitForm($edit, 'Apply to selected items');
$this->assertSession()->elementTextContains('css', 'h1', 'Are you sure you want to delete this enhanced entity with owner?');
$this->submitForm([], 'Delete');
// The entity is deleted in the web process, but will still be in the static
// cache of the test process, so we need to clear it manually.
$this->storage->resetCache([$id]);
$this->assertSession()->elementTextContains('css', 'h1', 'Enhanced entities with owner');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Status message"]', 'Deleted 1 item.');
$this->assertNull($this->storage->load($id));
}
/**
* Test the publish action on the bulk form.
*/
public function testPublishAction() {
/* @var \Drupal\entity_module_test\Entity\EnhancedEntityWithOwner $entity */
$entity = $this->storage->create([
'name' => 'Entity 1',
'type' => 'default',
'user_id' => $this->loggedInUser->id(),
'status' => 0,
]);
$entity->save();
$id = $entity->id();
$this->drupalGet($entity->toUrl('collection'));
$edit = [
'action' => 'entity_test_enhanced_with_owner_publish_action',
"entities[$id]" => $id,
];
$this->submitForm($edit, 'Apply to selected items');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Error message"]', 'No access to execute Publish enhanced entities with owner on the enhanced entity with owner Entity 1.');
$entity = $this->storage->load($id);
$this->assertFalse($entity->isPublished());
$account = $this->drupalCreateUser(array_merge(
$this->basePermissions,
['update any default entity_test_enhanced_with_owner']
));
$entity->setOwner($account)->save();
$this->drupalLogin($account);
$this->drupalGet($entity->toUrl('collection'));
$this->submitForm($edit, 'Apply to selected items');
// The entity is deleted in the web process, but will still be in the static
// cache of the test process, so we need to clear it manually.
$this->storage->resetCache([$id]);
$this->assertSession()->elementTextContains('css', 'h1', 'Enhanced entities with owner');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Status message"]', 'Publish enhanced entities with owner was applied to 1 item.');
$entity = $this->storage->load($id);
$this->assertTrue($entity->isPublished());
}
/**
* Test the unpublish action on the bulk form.
*/
public function testUnpublishAction() {
/* @var \Drupal\entity_module_test\Entity\EnhancedEntityWithOwner $entity */
$entity = $this->storage->create([
'name' => 'Entity 1',
'type' => 'default',
'user_id' => $this->loggedInUser->id(),
]);
$entity->save();
$id = $entity->id();
$this->drupalGet($entity->toUrl('collection'));
$edit = [
'action' => 'entity_test_enhanced_with_owner_unpublish_action',
"entities[$id]" => $id,
];
$this->submitForm($edit, 'Apply to selected items');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Error message"]', 'No access to execute Unpublish enhanced entities with owner on the enhanced entity with owner Entity 1.');
$entity = $this->storage->load($id);
$this->assertTrue($entity->isPublished());
$account = $this->drupalCreateUser(array_merge(
$this->basePermissions,
['update any default entity_test_enhanced_with_owner']
));
$entity->setOwner($account)->save();
$this->drupalLogin($account);
$this->drupalGet($entity->toUrl('collection'));
$this->submitForm($edit, 'Apply to selected items');
// The entity is deleted in the web process, but will still be in the static
// cache of the test process, so we need to clear it manually.
$this->storage->resetCache([$id]);
$this->assertSession()->elementTextContains('css', 'h1', 'Enhanced entities with owner');
$this->assertSession()->elementTextContains('xpath', '//div[@aria-label="Status message"]', 'Unpublish enhanced entities with owner was applied to 1 item.');
$entity = $this->storage->load($id);
$this->assertFalse($entity->isPublished());
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace Drupal\Tests\entity\Functional;
use Drupal\entity_module_test\Entity\EnhancedEntity;
use Drupal\Tests\block\Traits\BlockCreationTrait;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the collection route access check.
*
* @group entity
*
* @runTestsInSeparateProcesses
*
* @preserveGlobalState disabled
*/
class CollectionRouteAccessTest extends BrowserTestBase {
use BlockCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['entity_module_test', 'user', 'entity', 'block'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->placeBlock('local_tasks_block');
$this->placeBlock('system_breadcrumb_block');
}
/**
* Test the collection route access.
*/
public function testCollectionRouteAccess() {
$entity = EnhancedEntity::create([
'name' => 'rev 1',
'type' => 'default',
]);
$entity->save();
// User without any relevant permissions.
$account = $this->drupalCreateUser(['access administration pages']);
$this->drupalLogin($account);
$this->drupalGet($entity->toUrl('collection'));
$this->assertSession()->statusCodeEquals(403);
// User with "access overview" permissions.
$account = $this->drupalCreateUser(['access entity_test_enhanced overview']);
$this->drupalLogin($account);
$this->drupalGet($entity->toUrl('collection'));
$this->assertSession()->statusCodeEquals(200);
// User with full administration permissions.
$account = $this->drupalCreateUser(['administer entity_test_enhanced']);
$this->drupalLogin($account);
$this->drupalGet($entity->toUrl('collection'));
$this->assertSession()->statusCodeEquals(200);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Drupal\Tests\entity\Functional;
use Drupal\entity_module_test\Entity\EnhancedEntity;
use Drupal\Tests\block\Traits\BlockCreationTrait;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the entity duplicate UI.
*
* @group entity
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
*/
class EntityDuplicateTest extends BrowserTestBase {
use BlockCreationTrait;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $account;
/**
* The entity_test_enhanced storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected static $modules = ['entity_module_test', 'user', 'entity', 'block', 'views'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->placeBlock('local_tasks_block');
$this->placeBlock('page_title_block');
$this->placeBlock('system_breadcrumb_block');
$this->account = $this->drupalCreateUser([
'administer entity_test_enhanced',
]);
$this->drupalLogin($this->account);
$this->storage = $this->container->get('entity_type.manager')->getStorage('entity_test_enhanced');
}
/**
* Tests the duplicate form.
*/
public function testForm() {
$entity = EnhancedEntity::create([
'name' => 'Test',
'type' => 'default',
]);
$entity->save();
$this->drupalGet($entity->toUrl('duplicate-form'));
$this->assertSession()->pageTextContains('Duplicate Test');
$this->submitForm(['name[0][value]' => 'Test2'], 'Save');
$this->assertSession()->pageTextContains('Saved the Test2 enhanced entity.');
$this->storage->resetCache();
$entity = EnhancedEntity::load('1');
$this->assertEquals('Test', $entity->label());
$duplicated_entity = EnhancedEntity::load('2');
$this->assertEquals('Test2', $duplicated_entity->label());
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\entity\Functional\Menu;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that entity local actions are generated correctly.
*
* @group entity
*
* @runTestsInSeparateProcesses
*
* @preserveGlobalState disabled
*/
class EntityLocalActionTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['block', 'entity', 'entity_module_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->drupalPlaceBlock('local_actions_block');
$account = $this->drupalCreateUser(['administer entity_test_enhanced']);
$this->drupalLogin($account);
}
/**
* Tests the local action on the collection is provided correctly.
*/
public function testCollectionLocalAction() {
$this->drupalGet('/entity_test_enhanced');
$this->assertSession()->linkByHrefExists('/entity_test_enhanced/add?destination=/entity_test_enhanced');
$this->assertSession()->linkExists('Add enhanced entity');
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace Drupal\Tests\entity\Functional\Menu;
use Drupal\entity_module_test\Entity\EnhancedEntity;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that entity local tasks are generated correctly.
*
* @group entity
*
* @runTestsInSeparateProcesses
*
* @preserveGlobalState disabled
*/
class EntityLocalTaskTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['block', 'entity', 'entity_module_test'];
/**
* The view path of the entity used in the test.
*
* @var string
*/
protected $viewPath;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$entity = EnhancedEntity::create([
'type' => 'default',
'name' => 'Enhanced Entity test'
]);
$entity->save();
$this->viewPath = $entity->toUrl()->toString();
$this->drupalPlaceBlock('local_tasks_block');
$account = $this->drupalCreateUser(['administer entity_test_enhanced']);
$this->drupalLogin($account);
}
/**
* Tests the local tasks of the entity are provided correctly.
*/
public function testCollectionLocalAction() {
$this->drupalGet($this->viewPath);
$this->assertLocalTasks();
$this->clickLink('Edit');
$this->assertLocalTasks();
$this->clickLink('Duplicate');
$this->assertLocalTasks();
$this->clickLink('Revisions');
$this->assertLocalTasks();
}
/**
* Asserts that the entity's local tasks are visible.
*/
protected function assertLocalTasks() {
$this->assertSession()->linkByHrefExists($this->viewPath);
$this->assertSession()->linkExists('View');
$this->assertSession()->linkByHrefExists("$this->viewPath/edit");
$this->assertSession()->linkExists('Edit');
$this->assertSession()->linkByHrefExists("$this->viewPath/duplicate");
$this->assertSession()->linkExists('Duplicate');
$this->assertSession()->linkByHrefExists("$this->viewPath/revisions");
$this->assertSession()->linkExists('Revisions');
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Drupal\Tests\entity\Functional;
use Drupal\entity_module_test\Entity\EnhancedEntity;
use Drupal\Tests\block\Traits\BlockCreationTrait;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the revision route access check.
*
* @group entity
*
* @runTestsInSeparateProcesses
*
* @preserveGlobalState disabled
*/
class RevisionRouteAccessTest extends BrowserTestBase {
use BlockCreationTrait;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $account;
/**
* {@inheritdoc}
*/
protected static $modules = ['entity_module_test', 'user', 'entity', 'block'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->placeBlock('local_tasks_block');
$this->placeBlock('system_breadcrumb_block');
$this->account = $this->drupalCreateUser([
'administer entity_test_enhanced',
'view all entity_test_enhanced revisions',
]);
$this->drupalLogin($this->account);
}
/**
* Test enhanced entity revision routes access.
*/
public function testRevisionRouteAccess() {
$entity = EnhancedEntity::create([
'name' => 'rev 1',
'type' => 'default',
]);
$entity->save();
$revision = clone $entity;
$revision->name->value = 'rev 2';
$revision->setNewRevision(TRUE);
$revision->isDefaultRevision(FALSE);
$revision->save();
$this->drupalGet('/entity_test_enhanced/1/revisions');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseContains('Revisions');
$collection_link = $this->getSession()->getPage()->findLink('Enhanced entities');
$collection_link->click();
$this->assertSession()->addressEquals('/entity_test_enhanced');
$this->assertSession()->responseContains('Edit');
$edit_link = $this->getSession()->getPage()->findLink('Edit');
$edit_link->click();
$this->assertSession()->addressEquals('/entity_test_enhanced/1/edit');
// Check if we have revision tab link on edit page.
$this->getSession()->getPage()->findLink('Revisions')->click();
$this->assertSession()->addressEquals('/entity_test_enhanced/1/revisions');
$this->drupalGet('/entity_test_enhanced/1/revisions/2/view');
$this->assertSession()->statusCodeEquals(200);
$this->assertSession()->responseContains('rev 2');
$revisions_link = $this->getSession()->getPage()->findLink('Revisions');
$revisions_link->click();
$this->assertSession()->addressEquals('/entity_test_enhanced/1/revisions');
$this->assertSession()->statusCodeEquals(200);
}
}

View File

@@ -0,0 +1,290 @@
<?php
namespace Drupal\Tests\entity\Kernel;
use Drupal\entity_test\Entity\EntityTestBundle;
use Drupal\entity_test\Entity\EntityTestWithBundle;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\system\Entity\Action;
/**
* Tests the bundle entity duplicator.
*
* @coversDefaultClass \Drupal\entity\BundleEntityDuplicator
* @group entity
*/
class BundleEntityDuplicatorTest extends EntityKernelTestBase {
/**
* A test bundle entity.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityInterface
*/
protected $bundleEntity;
/**
* The bundle entity duplicator.
*
* @var \Drupal\entity\BundleEntityDuplicator
*/
protected $duplicator;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('action');
$this->bundleEntity = EntityTestBundle::create([
'id' => 'test',
'label' => 'Test',
'description' => 'This is the original description!',
]);
$this->bundleEntity->save();
$this->duplicator = $this->container->get('entity.bundle_entity_duplicator');
}
/**
* @covers ::duplicate
*/
public function testDuplicateInvalidEntity() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The "action" entity type is not a bundle entity type.');
$this->duplicator->duplicate(Action::create(), []);
}
/**
* @covers ::duplicate
*/
public function testDuplicateNoId() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The $values[\'id\'] key is empty or missing.');
$this->duplicator->duplicate($this->bundleEntity, []);
}
/**
* @covers ::duplicate
*/
public function testDuplicate() {
$duplicated_bundle_entity = $this->duplicator->duplicate($this->bundleEntity, [
'id' => 'test2',
'label' => 'Test2',
]);
$this->assertFalse($duplicated_bundle_entity->isNew());
$this->assertEquals('test2', $duplicated_bundle_entity->id());
$this->assertEquals('Test2', $duplicated_bundle_entity->label());
$this->assertEquals($this->bundleEntity->get('description'), $duplicated_bundle_entity->get('description'));
}
/**
* @covers ::duplicate
* @covers ::duplicateFields
* @covers ::duplicateDisplays
*/
public function testDuplicateWithFieldAndDisplays() {
$this->createTextField('field_text', 'test', 'Test text');
$form_display = $this->getDisplay('entity_test_with_bundle', 'test', 'form');
$form_display->setComponent('field_text', [
'type' => 'text_textfield',
'weight' => 0,
]);
$form_display->save();
$view_display = $this->getDisplay('entity_test_with_bundle', 'test', 'view');
$view_display->setComponent('field_text', [
'type' => 'text_default',
'weight' => 0,
]);
$view_display->save();
$duplicated_bundle_entity = $this->duplicator->duplicate($this->bundleEntity, [
'id' => 'test2',
'label' => 'Test2',
]);
$this->assertFalse($duplicated_bundle_entity->isNew());
$this->assertEquals('test2', $duplicated_bundle_entity->id());
$this->assertEquals('Test2', $duplicated_bundle_entity->label());
$this->assertEquals($this->bundleEntity->get('description'), $duplicated_bundle_entity->get('description'));
// Confirm that the field was copied to the new bundle.
$entity = EntityTestWithBundle::create(['type' => 'test2']);
$this->assertTrue($entity->hasField('field_text'));
// Confirm that the entity displays were copied.
$form_display = $this->getDisplay('entity_test_with_bundle', 'test2', 'form');
$this->assertNotEmpty($form_display->getComponent('field_text'));
$view_display = $this->getDisplay('entity_test_with_bundle', 'test2', 'view');
$this->assertNotEmpty($view_display->getComponent('field_text'));
}
/**
* @covers ::duplicateFields
*/
public function testDuplicateFieldsInvalidEntity() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The "action" entity type is not a bundle entity type.');
$this->duplicator->duplicateFields(Action::create(), 'test2');
}
/**
* @covers ::duplicateFields
*/
public function testDuplicateFieldsEmptyTarget() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The $target_bundle_id must not be empty.');
$this->duplicator->duplicateFields($this->bundleEntity, '');
}
/**
* @covers ::duplicateFields
*/
public function testDuplicateFields() {
$this->createTextField('field_text', 'test', 'Test text');
$this->createTextField('field_text2', 'test', 'Test text2');
$second_bundle_entity = EntityTestBundle::create([
'id' => 'test2',
'label' => 'Test2',
]);
$second_bundle_entity->save();
$entity = EntityTestWithBundle::create(['type' => 'test2']);
$this->assertFalse($entity->hasField('field_text'));
$this->assertFalse($entity->hasField('field_text2'));
$this->duplicator->duplicateFields($this->bundleEntity, 'test2');
$entity = EntityTestWithBundle::create(['type' => 'test2']);
$this->assertTrue($entity->hasField('field_text'));
$this->assertTrue($entity->hasField('field_text2'));
}
/**
* @covers ::duplicateDisplays
*/
public function testDuplicateDisplaysInvalidEntity() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The "action" entity type is not a bundle entity type.');
$this->duplicator->duplicateDisplays(Action::create(), 'test2');
}
/**
* @covers ::duplicateDisplays
*/
public function testDuplicateDisplaysEmptyTarget() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('The $target_bundle_id must not be empty.');
$this->duplicator->duplicateDisplays($this->bundleEntity, '');
}
/**
* @covers ::duplicateDisplays
*/
public function testDuplicateDisplays() {
$this->createTextField('field_text', 'test', 'Test text');
$form_display = $this->getDisplay('entity_test_with_bundle', 'test', 'form');
$form_display->setComponent('field_text', [
'type' => 'text_textfield',
'weight' => 0,
]);
$form_display->save();
$view_display = $this->getDisplay('entity_test_with_bundle', 'test', 'view');
$view_display->setComponent('field_text', [
'type' => 'text_default',
'weight' => 0,
]);
$view_display->save();
$second_bundle_entity = EntityTestBundle::create([
'id' => 'test2',
'label' => 'Test2',
]);
$second_bundle_entity->save();
FieldConfig::create([
'entity_type' => 'entity_test_with_bundle',
'field_name' => 'field_text',
'bundle' => 'test2',
'label' => 'Test text',
])->save();
$this->duplicator->duplicateDisplays($this->bundleEntity, 'test2');
$form_display = $this->getDisplay('entity_test_with_bundle', 'test2', 'form');
$this->assertNotEmpty($form_display->getComponent('field_text'));
$view_display = $this->getDisplay('entity_test_with_bundle', 'test2', 'view');
$this->assertNotEmpty($view_display->getComponent('field_text'));
}
/**
* Creates a text field on the "entity_test_with_bundle" entity.
*
* @param string $field_name
* The field name.
* @param string $bundle
* The target bundle.
* @param string $label
* The field label.
*/
protected function createTextField($field_name, $bundle, $label) {
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'entity_test_with_bundle',
'type' => 'text',
'cardinality' => 1,
])->save();
FieldConfig::create([
'entity_type' => 'entity_test_with_bundle',
'field_name' => $field_name,
'bundle' => $bundle,
'label' => $label,
])->save();
}
/**
* Gets the entity display for the given entity type and bundle.
*
* The entity display will be created if missing.
*
* @param string $entity_type
* The entity type.
* @param string $bundle
* The bundle.
* @param string $display_context
* The display context ('view' or 'form').
*
* @throws \InvalidArgumentException
* Thrown when an invalid display context is provided.
*
* @return \Drupal\Core\Entity\Display\EntityDisplayInterface
* The entity display.
*/
protected function getDisplay($entity_type, $bundle, $display_context) {
if (!in_array($display_context, ['view', 'form'])) {
throw new \InvalidArgumentException(sprintf('Invalid display_context %s passed to _commerce_product_get_display().', $display_context));
}
$entity_type_manager = $this->container->get('entity_type.manager');
$storage = $entity_type_manager->getStorage('entity_' . $display_context . '_display');
$display = $storage->load($entity_type . '.' . $bundle . '.default');
if (!$display) {
$display = $storage->create([
'targetEntityType' => $entity_type,
'bundle' => $bundle,
'mode' => 'default',
'status' => TRUE,
]);
}
return $display;
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace Drupal\Tests\entity\Kernel;
use Drupal\entity_module_bundle_plugin_test\Entity\EntityTestBundlePlugin;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the bundle plugin API.
*
* @group entity
*/
class BundlePluginTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'system',
'entity',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Install the modules properly. Putting them into static::$modules doesn't trigger the install
// hooks, like hook_modules_installed, so entity_modules_installed is not triggered().
/** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
$module_installer = $this->container->get('module_installer');
$module_installer->install(['entity_module_bundle_plugin_test', 'entity_module_bundle_plugin_examples_test']);
}
/**
* Tests the bundle plugins.
*/
public function testPluginBundles() {
$bundled_entity_types = entity_get_bundle_plugin_entity_types();
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
$entity_type = $bundled_entity_types['entity_test_bundle_plugin'];
$this->assertEquals('entity_test_bundle_plugin', $entity_type->id());
$this->assertTrue($entity_type->hasHandlerClass('bundle_plugin'));
/** @var \Drupal\Core\Entity\EntityTypeBundleInfo $entity_type_bundle_info */
$entity_type_bundle_info = $this->container->get('entity_type.bundle.info');
$bundle_info = $entity_type_bundle_info->getBundleInfo('entity_test_bundle_plugin');
$this->assertEquals(2, count($bundle_info));
$this->assertArrayHasKey('first', $bundle_info);
$this->assertArrayHasKey('second', $bundle_info);
$this->assertEquals('First', $bundle_info['first']['label']);
$this->assertEquals('Some description', $bundle_info['first']['description']);
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
$entity_field_manager = $this->container->get('entity_field.manager');
$field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions('entity_test_bundle_plugin');
$this->assertArrayHasKey('first_mail', $field_storage_definitions);
$this->assertArrayHasKey('second_mail', $field_storage_definitions);
$first_field_definitions = $entity_field_manager->getFieldDefinitions('entity_test_bundle_plugin', 'first');
$this->assertArrayHasKey('first_mail', $first_field_definitions);
$this->assertArrayNotHasKey('second_mail', $first_field_definitions);
$second_field_definitions = $entity_field_manager->getFieldDefinitions('entity_test_bundle_plugin', 'second');
$this->assertArrayNotHasKey('first_mail', $second_field_definitions);
$this->assertArrayHasKey('second_mail', $second_field_definitions);
$first_entity = EntityTestBundlePlugin::create([
'type' => 'first',
'first_mail' => 'admin@test.com',
]);
$first_entity->save();
$first_entity = EntityTestBundlePlugin::load($first_entity->id());
$this->assertEquals('admin@test.com', $first_entity->first_mail->value);
$second_entity = EntityTestBundlePlugin::create([
'type' => 'second',
'second_mail' => 'admin@example.com',
]);
$second_entity->save();
$second_entity = EntityTestBundlePlugin::load($second_entity->id());
$this->assertEquals('admin@example.com', $second_entity->second_mail->value);
// Also test entity queries.
$result = $this->container->get('entity_type.manager')->getStorage('entity_test_bundle_plugin')
->getQuery()
->condition('second_mail', 'admin@example.com')
->accessCheck(TRUE)
->execute();
$this->assertEquals([$second_entity->id() => $second_entity->id()], $result);
$result = $this->container->get('entity_type.manager')->getStorage('entity_test_bundle_plugin')
->getQuery()
->condition('type', 'first')
->accessCheck(TRUE)
->execute();
$this->assertEquals([$first_entity->id() => $first_entity->id()], $result);
}
/**
* Tests the uninstallation for a bundle provided by a module.
*/
public function testBundlePluginModuleUninstallation() {
/** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
$module_installer = $this->container->get('module_installer');
// One should be possible to uninstall without any actual content.
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_examples_test']);
$this->assertEmpty($violations);
$first_entity = EntityTestBundlePlugin::create([
'type' => 'first',
'first_mail' => 'admin@test.com',
]);
$first_entity->save();
$second_entity = EntityTestBundlePlugin::create([
'type' => 'second',
'second_mail' => 'admin@example.com',
]);
$second_entity->save();
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_examples_test']);
$this->assertCount(1, $violations);
$this->assertCount(1, $violations['entity_module_bundle_plugin_examples_test']);
$this->assertEquals('There is data for the bundle Second on the entity type Entity test bundle plugin. Please remove all content before uninstalling the module.', $violations['entity_module_bundle_plugin_examples_test'][0]);
$second_entity->delete();
// The first entity is defined by entity_module_bundle_plugin_test, so it should be possible
// to uninstall the module providing the second bundle plugin.
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_examples_test']);
$this->assertEmpty($violations);
$module_installer->uninstall(['entity_module_bundle_plugin_examples_test']);
// The first entity is provided by entity_module_bundle_plugin_test which we cannot uninstall,
// until all the entities are deleted.
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_test']);
$this->assertNotEmpty($violations);
$first_entity->delete();
$violations = $module_installer->validateUninstall(['entity_module_bundle_plugin_test']);
$this->assertEmpty($violations);
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\entity\QueryAccess\Condition;
use Drupal\entity\QueryAccess\ConditionGroup;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the condition group class.
*
* ConditionGroup uses \Drupal\Core\Cache\Cache internally, which makes it
* impossible to use a unit test (due to Cache accessing the global container).
*
* @coversDefaultClass \Drupal\entity\QueryAccess\ConditionGroup
* @group entity
*/
class ConditionGroupTest extends KernelTestBase {
/**
* ::covers getConjunction
* ::covers addCondition
* ::covers getConditions
* ::covers count.
*/
public function testGetters() {
$condition_group = new ConditionGroup();
$condition_group->addCondition('uid', '2');
$this->assertEquals('AND', $condition_group->getConjunction());
$expected_conditions = [
new Condition('uid', '2'),
];
$this->assertEquals($expected_conditions, $condition_group->getConditions());
$this->assertEquals(1, $condition_group->count());
$this->assertEquals("uid = '2'", $condition_group->__toString());
$condition_group = new ConditionGroup('OR');
$condition_group->addCondition('type', ['article', 'page']);
$condition_group->addCondition('status', '1', '<>');
$this->assertEquals('OR', $condition_group->getConjunction());
$expected_conditions = [
new Condition('type', ['article', 'page']),
new Condition('status', '1', '<>'),
];
$expected_lines = [
"(",
" type IN ['article', 'page']",
" OR",
" status <> '1'",
")",
];
$this->assertEquals($expected_conditions, $condition_group->getConditions());
$this->assertEquals(2, $condition_group->count());
$this->assertEquals(implode("\n", $expected_lines), $condition_group->__toString());
// Nested condition group with a single condition.
$condition_group = new ConditionGroup();
$condition_group->addCondition('type', ['article', 'page']);
$condition_group->addCondition((new ConditionGroup('AND'))
->addCondition('status', '1')
);
$expected_conditions = [
new Condition('type', ['article', 'page']),
new Condition('status', '1'),
];
$expected_lines = [
"(",
" type IN ['article', 'page']",
" AND",
" status = '1'",
")",
];
$this->assertEquals($expected_conditions, $condition_group->getConditions());
$this->assertEquals('AND', $condition_group->getConjunction());
$this->assertEquals(2, $condition_group->count());
$this->assertEquals(implode("\n", $expected_lines), $condition_group->__toString());
// Nested condition group with multiple conditions.
$condition_group = new ConditionGroup();
$condition_group->addCondition('type', ['article', 'page']);
$nested_condition_group = new ConditionGroup('OR');
$nested_condition_group->addCondition('uid', '1');
$nested_condition_group->addCondition('status', '1');
$condition_group->addCondition($nested_condition_group);
$expected_conditions = [
new Condition('type', ['article', 'page']),
$nested_condition_group,
];
$expected_lines = [
"(",
" type IN ['article', 'page']",
" AND",
" (",
" uid = '1'",
" OR",
" status = '1'",
" )",
")",
];
$this->assertEquals($expected_conditions, $condition_group->getConditions());
$this->assertEquals('AND', $condition_group->getConjunction());
$this->assertEquals(2, $condition_group->count());
$this->assertEquals(implode("\n", $expected_lines), $condition_group->__toString());
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Render\RenderContext;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
/**
* Tests the generic query access handler.
*
* @coversDefaultClass \Drupal\entity\QueryAccess\EventOnlyQueryAccessHandler
* @group entity
*/
class EventOnlyQueryAccessHandlerTest extends EntityKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
'entity_module_test',
'node',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('node');
\Drupal::state()->set('test_event_only_query_access', TRUE);
}
/**
* Tests cacheability with the event only query_access handler.
*
* If there is no additional cacheability provided to the conditions, there
* should be no render contexts leaked.
*/
public function testCacheableMetadataLeaks() {
$renderer = $this->container->get('renderer');
$render_context = new RenderContext();
$node_type_storage = $this->entityTypeManager->getStorage('node_type');
$node_type_storage->create(['type' => 'foo', 'name' => $this->randomString()])->save();
$node_storage = $this->entityTypeManager->getStorage('node');
$node_1 = $node_storage->create(['type' => 'foo', 'title' => $this->randomString()]);
$node_1->save();
$node_2 = $node_storage->create(['type' => 'bar', 'title' => $this->randomString()]);
$node_2->save();
$renderer->executeInRenderContext($render_context, static function () use ($node_storage) {
$node_storage->getQuery()->accessCheck(TRUE)->execute();
});
$this->assertTrue($render_context->isEmpty(), 'Empty cacheability was not bubbled.');
$cacheability = new CacheableMetadata();
$cacheability->addCacheContexts(['user.permissions']);
\Drupal::state()->set('event_only_query_access_cacheability', $cacheability);
$render_context = new RenderContext();
$renderer->executeInRenderContext($render_context, static function () use ($node_storage) {
$node_storage->getQuery()->accessCheck(TRUE)->execute();
});
$this->assertFalse($render_context->isEmpty(), 'Cacheability was bubbled');
$this->assertCount(1, $render_context);
$this->assertEquals(['user.permissions'], $render_context[0]->getCacheContexts());
}
/**
* Tests that entity types without a query access handler still fire events.
*/
public function testEventOnlyQueryAccessHandlerEventSubscriber() {
$node_type_storage = $this->entityTypeManager->getStorage('node_type');
$node_type_storage->create(['type' => 'foo', 'name' => $this->randomString()])->save();
$node_type_storage->create(['type' => 'bar', 'name' => $this->randomString()])->save();
$node_storage = $this->entityTypeManager->getStorage('node');
$node_1 = $node_storage->create(['type' => 'foo', 'title' => $this->randomString()]);
$node_1->save();
$node_2 = $node_storage->create(['type' => 'bar', 'title' => $this->randomString()]);
$node_2->save();
$unfiltered = $node_storage->getQuery()->accessCheck(FALSE)->execute();
$this->assertCount(2, $unfiltered, 'Both nodes show up when access checking is turned off.');
$this->assertArrayHasKey($node_1->id(), $unfiltered, 'foo nodes were not filtered out.');
$this->assertArrayHasKey($node_2->id(), $unfiltered, 'bar nodes were not filtered out.');
$filtered = $node_storage->getQuery()->accessCheck(TRUE)->execute();
$this->assertCount(1, $filtered, 'Only one node shows up when access checking is turned on.');
$this->assertArrayHasKey($node_1->id(), $filtered, 'foo nodes were not filtered out.');
$this->assertArrayNotHasKey($node_2->id(), $filtered, 'bar nodes were filtered out.');
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\entity\QueryAccess\QueryAccessHandler;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
/**
* Tests the query access event.
*
* @group entity
*/
class QueryAccessEventTest extends EntityKernelTestBase {
/**
* The query access handler.
*
* @var \Drupal\entity\QueryAccess\QueryAccessHandler
*/
protected $handler;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
'entity_module_test',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('entity_test_enhanced');
// Create uid: 1 here so that it's skipped in test cases.
$admin_user = $this->createUser();
$entity_type_manager = $this->container->get('entity_type.manager');
$entity_type = $entity_type_manager->getDefinition('entity_test_enhanced');
$this->handler = QueryAccessHandler::createInstance($this->container, $entity_type);
}
/**
* Tests the generic event.
*/
public function testGenericEvent() {
$entity_type_manager = $this->container->get('entity_type.manager');
$entity_type = $entity_type_manager->getDefinition('entity_test_enhanced_with_owner');
$handler = QueryAccessHandler::createInstance($this->container, $entity_type);
$first_user = $this->createUser([], NULL, FALSE, ['mail' => 'user9000@example.com']);
$conditions = $handler->getConditions('view', $first_user);
$this->assertTrue($conditions->isAlwaysFalse());
$second_user = $this->createUser([], NULL, FALSE, ['mail' => 'user9001@example.com']);
$conditions = $handler->getConditions('view', $second_user);
$this->assertFalse($conditions->isAlwaysFalse());
}
/**
* Tests the event.
*/
public function testEvent() {
// By default, the first user should have full access, and the second
// user should have no access. The QueryAccessSubscriber flips that.
$first_user = $this->createUser(['administer entity_test_enhanced'], NULL, FALSE, ['mail' => 'user1@example.com']);
$second_user = $this->createUser([], NULL, FALSE, ['mail' => 'user2@example.com']);
$conditions = $this->handler->getConditions('view', $first_user);
$this->assertTrue($conditions->isAlwaysFalse());
$conditions = $this->handler->getConditions('view', $second_user);
$this->assertFalse($conditions->isAlwaysFalse());
}
}

View File

@@ -0,0 +1,129 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\entity\QueryAccess\Condition;
use Drupal\entity\QueryAccess\QueryAccessHandler;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
/**
* Tests the query access handler.
*
* Uses the "entity_test_enhanced" entity type, which has no owner.
* UncacheableQueryAccessHandlerTest uses the "entity_test_enhanced_with_owner"
* entity type, which has an owner. This ensures both sides (owner and
* no owner) are covered.
*
* @coversDefaultClass \Drupal\entity\QueryAccess\QueryAccessHandler
* @group entity
*/
class QueryAccessHandlerTest extends EntityKernelTestBase {
/**
* The query access handler.
*
* @var \Drupal\entity\QueryAccess\QueryAccessHandler
*/
protected $handler;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
'entity_module_test',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('entity_test_enhanced');
// Create uid: 1 here so that it's skipped in test cases.
$admin_user = $this->createUser();
$entity_type_manager = $this->container->get('entity_type.manager');
$entity_type = $entity_type_manager->getDefinition('entity_test_enhanced');
$this->handler = QueryAccessHandler::createInstance($this->container, $entity_type);
}
/**
* @covers ::getConditions
*/
public function testNoAccess() {
foreach (['view', 'update', 'duplicate', 'delete'] as $operation) {
$user = $this->createUser(['access content']);
$conditions = $this->handler->getConditions($operation, $user);
$this->assertEquals(0, $conditions->count());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertTrue($conditions->isAlwaysFalse());
}
}
/**
* @covers ::getConditions
*/
public function testAdmin() {
foreach (['view', 'update', 'duplicate', 'delete'] as $operation) {
$user = $this->createUser(['administer entity_test_enhanced']);
$conditions = $this->handler->getConditions($operation, $user);
$this->assertEquals(0, $conditions->count());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
}
}
/**
* @covers ::getConditions
*/
public function testView() {
// Entity type permission.
$user = $this->createUser(['view entity_test_enhanced']);
$conditions = $this->handler->getConditions('view', $user);
$expected_conditions = [
new Condition('status', '1'),
];
$this->assertEquals(1, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
// Bundle permission.
$user = $this->createUser(['view first entity_test_enhanced']);
$conditions = $this->handler->getConditions('view', $user);
$expected_conditions = [
new Condition('type', ['first']),
new Condition('status', '1'),
];
$this->assertEquals('AND', $conditions->getConjunction());
$this->assertEquals(2, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
}
/**
* @covers ::getConditions
*/
public function testUpdateDuplicateDelete() {
foreach (['update', 'duplicate', 'delete'] as $operation) {
$user = $this->createUser([
"$operation first entity_test_enhanced",
"$operation second entity_test_enhanced",
]);
$conditions = $this->handler->getConditions($operation, $user);
$expected_conditions = [
new Condition('type', ['first', 'second']),
];
$this->assertEquals('OR', $conditions->getConjunction());
$this->assertEquals(1, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
}
}
}

View File

@@ -0,0 +1,394 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\entity_module_test\Entity\EnhancedEntity;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\views\Tests\ViewResultAssertionTrait;
use Drupal\views\Views;
/**
* Test query access filtering for EntityQuery and Views.
*
* @group entity
*
* @see \Drupal\entity\QueryAccess\QueryAccessHandler
* @see \Drupal\entity\QueryAccess\EntityQueryAlter
* @see \Drupal\entity\QueryAccess\ViewsQueryAlter
*/
class QueryAccessTest extends EntityKernelTestBase {
use ViewResultAssertionTrait;
/**
* The test entities.
*
* @var \Drupal\Core\Entity\ContentEntityInterface[]
*/
protected $entities;
/**
* The entity_test_enhanced storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
'entity_module_test',
'user',
'views',
'system',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('entity_test_enhanced');
$this->installConfig(['entity_module_test']);
// Create uid: 1 here so that it's skipped in test cases.
$admin_user = $this->createUser();
$first_entity = EnhancedEntity::create([
'type' => 'first',
'label' => 'First',
'status' => 1,
]);
$first_entity->save();
$first_entity->set('name', 'First!');
$first_entity->set('status', 0);
$first_entity->setNewRevision(TRUE);
$first_entity->save();
$second_entity = EnhancedEntity::create([
'type' => 'first',
'label' => 'Second',
'status' => 0,
]);
$second_entity->save();
$second_entity->set('name', 'Second!');
$second_entity->set('status', 1);
$second_entity->setNewRevision(TRUE);
$second_entity->save();
$third_entity = EnhancedEntity::create([
'type' => 'second',
'label' => 'Third',
'status' => 1,
]);
$third_entity->save();
$third_entity->set('name', 'Third!');
$third_entity->setNewRevision(TRUE);
$third_entity->save();
$this->entities = [$first_entity, $second_entity, $third_entity];
$this->storage = $this->entityTypeManager->getStorage('entity_test_enhanced');
}
/**
* Tests EntityQuery filtering.
*/
public function testEntityQuery() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced']);
$this->container->get('current_user')->setAccount($admin_user);
$result = $this->storage->getQuery()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
$this->entities[0]->id(),
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->accessCheck(TRUE)->execute();
$this->assertEmpty($result);
// View (published-only).
$user = $this->createUser(['view entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
// View $bundle (published-only).
$user = $this->createUser(['view first entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[1]->id(),
], array_values($result));
}
/**
* Tests EntityQuery filtering when all revisions are queried.
*/
public function testEntityQueryWithRevisions() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced']);
$this->container->get('current_user')->setAccount($admin_user);
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'2' => $this->entities[0]->id(),
'3' => $this->entities[1]->id(),
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
'6' => $this->entities[2]->id(),
], $result);
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->accessCheck(TRUE)->execute();
$this->assertEmpty($result);
// View (published-only).
$user = $this->createUser(['view entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
'6' => $this->entities[2]->id(),
], $result);
// View $bundle (published-only).
$user = $this->createUser(['view first entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'4' => $this->entities[1]->id(),
], $result);
}
/**
* Tests Views filtering.
*/
public function testViews() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced']);
$this->container->get('current_user')->setAccount($admin_user);
$view = Views::getView('entity_test_enhanced');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[0]->id()],
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced');
$view->execute();
$this->assertIdenticalResultset($view, []);
// View (published-only).
$user = $this->createUser(['view entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
// View $bundle (published-only).
$user = $this->createUser(['view first entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[1]->id()],
], ['id' => 'id']);
}
/**
* Tests Views filtering when all revisions are queried.
*/
public function testViewsWithRevisions() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced']);
$this->container->get('current_user')->setAccount($admin_user);
$view = Views::getView('entity_test_enhanced_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '2', 'id' => $this->entities[0]->id()],
['vid' => '3', 'id' => $this->entities[1]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
['vid' => '6', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced');
$view->execute();
$this->assertIdenticalResultset($view, []);
// View (published-only).
$user = $this->createUser(['view entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
['vid' => '6', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
// View $bundle (published-only).
$user = $this->createUser(['view first entity_test_enhanced']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
], ['vid' => 'vid']);
}
/**
* Tests no filtering when query access is disabled.
*/
public function testNoFiltering() {
// EntityQuery.
$result = $this->storage->getQuery()->sort('id')->accessCheck(FALSE)->execute();
$this->assertEquals([
$this->entities[0]->id(),
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
// Views.
$view = Views::getView('entity_test_enhanced');
$display = $view->getDisplay();
$display_options = $display->getOption('query');
$display_options['options']['disable_sql_rewrite'] = TRUE;
$display->setOption('query', $display_options);
$view->save();
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[0]->id()],
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
$view = Views::getView('entity_test_enhanced');
$display = $view->getDisplay();
$display_options['options']['disable_sql_rewrite'] = FALSE;
$display->setOption('query', $display_options);
$view->save();
}
/**
* Tests filtering based on a configurable field.
*
* QueryAccessSubscriber adds a condition that ensures that the field value
* is either empty or matches "marketing".
*
* @see \Drupal\entity_module_test\EventSubscriber\QueryAccessSubscriber
*/
public function testConfigurableField() {
$this->entities[0]->set('assigned', 'marketing');
$this->entities[0]->save();
// The field is case sensitive, so the third entity should be ignored.
$this->entities[2]->set('assigned', 'MarKeTing');
$this->entities[2]->save();
$user = $this->createUser(['access content'], NULL, FALSE, [
'mail' => 'user3@example.com',
]);
$this->container->get('current_user')->setAccount($user);
// EntityQuery.
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[0]->id(),
$this->entities[1]->id(),
], array_values($result));
// EntityQuery with revisions.
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'2' => $this->entities[0]->id(),
'3' => $this->entities[1]->id(),
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
], $result);
// View.
$view = Views::getView('entity_test_enhanced');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[0]->id()],
['id' => $this->entities[1]->id()],
], ['id' => 'id']);
// View with revisions.
$view = Views::getView('entity_test_enhanced_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '2', 'id' => $this->entities[0]->id()],
['vid' => '3', 'id' => $this->entities[1]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\entity\QueryAccess\Condition;
use Drupal\entity\QueryAccess\ConditionGroup;
use Drupal\entity\QueryAccess\UncacheableQueryAccessHandler;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
/**
* Tests the uncacheable query access handler.
*
* Uses the "entity_test_enhanced_with_owner" entity type, which has an owner.
* QueryAccessHandlerTest uses the "entity_test_enhanced" entity type, which
* has no owner. This ensures both sides (owner and no owner) are covered.
*
* @coversDefaultClass \Drupal\entity\QueryAccess\UncacheableQueryAccessHandler
* @group entity
*/
class UncacheableQueryAccessHandlerTest extends EntityKernelTestBase {
/**
* The query access handler.
*
* @var \Drupal\entity\QueryAccess\UncacheableQueryAccessHandler
*/
protected $handler;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
'entity_module_test',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('entity_test_enhanced_with_owner');
// Create uid: 1 here so that it's skipped in test cases.
$admin_user = $this->createUser();
$entity_type_manager = $this->container->get('entity_type.manager');
$entity_type = $entity_type_manager->getDefinition('entity_test_enhanced_with_owner');
$this->handler = UncacheableQueryAccessHandler::createInstance($this->container, $entity_type);
}
/**
* @covers ::getConditions
*/
public function testNoAccess() {
foreach (['view', 'update', 'delete'] as $operation) {
$user = $this->createUser(['access content']);
$conditions = $this->handler->getConditions($operation, $user);
$this->assertEquals(0, $conditions->count());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertTrue($conditions->isAlwaysFalse());
}
}
/**
* @covers ::getConditions
*/
public function testAdmin() {
foreach (['view', 'update', 'delete'] as $operation) {
$user = $this->createUser(['administer entity_test_enhanced_with_owner']);
$conditions = $this->handler->getConditions($operation, $user);
$this->assertEquals(0, $conditions->count());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
}
}
/**
* @covers ::getConditions
*/
public function testView() {
// Any permission.
$user = $this->createUser(['view any entity_test_enhanced_with_owner']);
$conditions = $this->handler->getConditions('view', $user);
$expected_conditions = [
new Condition('status', '1'),
];
$this->assertEquals(1, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEquals(['user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
// Own permission.
$user = $this->createUser(['view own entity_test_enhanced_with_owner']);
$conditions = $this->handler->getConditions('view', $user);
$expected_conditions = [
new Condition('user_id', $user->id()),
new Condition('status', '1'),
];
$this->assertEquals('AND', $conditions->getConjunction());
$this->assertEquals(2, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEqualsCanonicalizing(['user', 'user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
// Any permission for the first bundle, own permission for the second.
$user = $this->createUser([
'view any first entity_test_enhanced_with_owner',
'view own second entity_test_enhanced_with_owner',
]);
$conditions = $this->handler->getConditions('view', $user);
$expected_conditions = [
(new ConditionGroup('OR'))
->addCacheContexts(['user', 'user.permissions'])
->addCondition('type', ['first'])
->addCondition((new ConditionGroup('AND'))
->addCondition('user_id', $user->id())
->addCondition('type', ['second'])
),
new Condition('status', '1'),
];
$this->assertEquals('AND', $conditions->getConjunction());
$this->assertEquals(2, $conditions->count());
$this->assertEqualsCanonicalizing($expected_conditions, $conditions->getConditions());
$this->assertEqualsCanonicalizing(['user', 'user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
// View own unpublished permission.
$user = $this->createUser(['view own unpublished entity_test_enhanced_with_owner']);
$conditions = $this->handler->buildConditions('view', $user);
$expected_conditions = [
new Condition('user_id', $user->id()),
new Condition('status', '0'),
];
$this->assertEquals(2, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEquals(['user'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
// Both view any and view own unpublished permissions.
$user = $this->createUser([
'view any entity_test_enhanced_with_owner',
'view own unpublished entity_test_enhanced_with_owner',
]);
$conditions = $this->handler->buildConditions('view', $user);
$expected_conditions = [
new Condition('status', '1'),
(new ConditionGroup('AND'))
->addCondition('user_id', $user->id())
->addCondition('status', '0')
->addCacheContexts(['user']),
];
$this->assertEquals(2, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEqualsCanonicalizing(['user', 'user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
}
/**
* @covers ::getConditions
*/
public function testUpdateDuplicateDelete() {
foreach (['update', 'duplicate', 'delete'] as $operation) {
// Any permission for the first bundle, own permission for the second.
$user = $this->createUser([
"$operation any first entity_test_enhanced_with_owner",
"$operation own second entity_test_enhanced_with_owner",
]);
$conditions = $this->handler->getConditions($operation, $user);
$expected_conditions = [
new Condition('type', ['first']),
(new ConditionGroup('AND'))
->addCondition('user_id', $user->id())
->addCondition('type', ['second']),
];
$this->assertEquals('OR', $conditions->getConjunction());
$this->assertEquals(2, $conditions->count());
$this->assertEquals($expected_conditions, $conditions->getConditions());
$this->assertEqualsCanonicalizing(['user', 'user.permissions'], $conditions->getCacheContexts());
$this->assertFalse($conditions->isAlwaysFalse());
}
}
}

View File

@@ -0,0 +1,535 @@
<?php
namespace Drupal\Tests\entity\Kernel\QueryAccess;
use Drupal\entity_module_test\Entity\EnhancedEntityWithOwner;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\views\Tests\ViewResultAssertionTrait;
use Drupal\views\Views;
/**
* Test uncacheable query access filtering for EntityQuery and Views.
*
* @group entity
*
* @see \Drupal\entity\QueryAccess\UncacheableQueryAccessHandler
* @see \Drupal\entity\QueryAccess\EntityQueryAlter
* @see \Drupal\entity\QueryAccess\ViewsQueryAlter
*/
class UncacheableQueryAccessTest extends EntityKernelTestBase {
use ViewResultAssertionTrait;
/**
* The test entities.
*
* @var \Drupal\Core\Entity\ContentEntityInterface[]
*/
protected $entities;
/**
* The entity_test_enhanced storage.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected static $modules = [
'entity',
'entity_module_test',
'user',
'views',
'system',
];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('entity_test_enhanced_with_owner');
$this->installConfig(['entity_module_test']);
// Create uid: 1 here so that it's skipped in test cases.
$admin_user = $this->createUser();
$first_entity = EnhancedEntityWithOwner::create([
'type' => 'first',
'name' => 'First',
'status' => 1,
]);
$first_entity->save();
$first_entity->set('name', 'First!');
$first_entity->set('status', 0);
$first_entity->setNewRevision(TRUE);
$first_entity->save();
$second_entity = EnhancedEntityWithOwner::create([
'type' => 'first',
'name' => 'Second',
'status' => 0,
]);
$second_entity->save();
$second_entity->set('name', 'Second!');
$second_entity->set('status', 1);
$second_entity->setNewRevision(TRUE);
$second_entity->save();
$third_entity = EnhancedEntityWithOwner::create([
'type' => 'second',
'name' => 'Third',
'status' => 1,
]);
$third_entity->save();
$third_entity->set('name', 'Third!');
$third_entity->setNewRevision(TRUE);
$third_entity->save();
$this->entities = [$first_entity, $second_entity, $third_entity];
$this->storage = $this->entityTypeManager->getStorage('entity_test_enhanced_with_owner');
}
/**
* Tests EntityQuery filtering.
*/
public function testEntityQuery() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($admin_user);
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[0]->id(),
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->accessCheck(TRUE)->execute();
$this->assertEmpty($result);
// View own (published-only).
$user = $this->createUser(['view own entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[1]->id(),
], array_values($result));
// View any (published-only).
$user = $this->createUser(['view any entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
// View own unpublished.
$user = $this->createUser(['view own unpublished entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[0]->id(),
], array_values($result));
// View own unpublished + view any (published-only).
$user = $this->createUser([
'view own unpublished entity_test_enhanced_with_owner',
'view any entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[0]->id(),
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
// View own $first_bundle + View any $second_bundle.
$user = $this->createUser([
'view own first entity_test_enhanced_with_owner',
'view any second entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$result = $this->storage->getQuery()->sort('id')->accessCheck(TRUE)->execute();
$this->assertEquals([
$this->entities[1]->id(),
$this->entities[2]->id(),
], array_values($result));
}
/**
* Tests EntityQuery filtering when all revisions are queried.
*/
public function testEntityQueryWithRevisions() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($admin_user);
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'2' => $this->entities[0]->id(),
'3' => $this->entities[1]->id(),
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
'6' => $this->entities[2]->id(),
], $result);
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()->allRevisions()->accessCheck(TRUE)->execute();
$this->assertEmpty($result);
// View own (published-only).
$user = $this->createUser(['view own entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
// The user_id field is not revisionable, which means that updating it
// will modify both revisions for each entity.
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'4' => $this->entities[1]->id(),
], $result);
// View any (published-only).
$user = $this->createUser(['view any entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
'6' => $this->entities[2]->id(),
], $result);
// View own unpublished.
$user = $this->createUser(['view own unpublished entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'2' => $this->entities[0]->id(),
'3' => $this->entities[1]->id(),
], $result);
// View own unpublished + view any (published-only).
$user = $this->createUser([
'view own unpublished entity_test_enhanced_with_owner',
'view any entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'1' => $this->entities[0]->id(),
'2' => $this->entities[0]->id(),
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
'6' => $this->entities[2]->id(),
], $result);
// View own $first_bundle + View any $second_bundle.
$user = $this->createUser([
'view own first entity_test_enhanced_with_owner',
'view any second entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$result = $this->storage->getQuery()
->allRevisions()
->sort('id')
->accessCheck(TRUE)
->execute();
$this->assertEquals([
'4' => $this->entities[1]->id(),
'5' => $this->entities[2]->id(),
'6' => $this->entities[2]->id(),
], $result);
}
/**
* Tests Views filtering.
*/
public function testViews() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($admin_user);
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[0]->id()],
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, []);
// View own (published-only).
$user = $this->createUser(['view own entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[1]->id()],
], ['id' => 'id']);
// View any (published-only).
$user = $this->createUser(['view any entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
// View own unpublished.
$user = $this->createUser(['view own unpublished entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[0]->id()],
], ['id' => 'id']);
// View own unpublished + view any (published-only).
$user = $this->createUser([
'view own unpublished entity_test_enhanced_with_owner',
'view any entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[0]->id()],
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
// View own $first_bundle + View any $second_bundle.
$user = $this->createUser([
'view own first entity_test_enhanced_with_owner',
'view any second entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$view = Views::getView('entity_test_enhanced_with_owner');
$view->execute();
$this->assertIdenticalResultset($view, [
['id' => $this->entities[1]->id()],
['id' => $this->entities[2]->id()],
], ['id' => 'id']);
}
/**
* Tests Views filtering when all revisions are queried.
*/
public function testViewsWithRevisions() {
// Admin permission, full access.
$admin_user = $this->createUser(['administer entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($admin_user);
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '2', 'id' => $this->entities[0]->id()],
['vid' => '3', 'id' => $this->entities[1]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
['vid' => '6', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
// No view permissions, no access.
$user = $this->createUser(['access content']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, []);
// View own (published-only).
$user = $this->createUser(['view own entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
], ['vid' => 'vid']);
// View any (published-only).
$user = $this->createUser(['view any entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
['vid' => '6', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
// View own unpublished.
$user = $this->createUser(['view own unpublished entity_test_enhanced_with_owner']);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '2', 'id' => $this->entities[0]->id()],
['vid' => '3', 'id' => $this->entities[1]->id()],
], ['vid' => 'vid']);
// View own unpublished + view any (published-only).
$user = $this->createUser([
'view own unpublished entity_test_enhanced_with_owner',
'view any entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[0]->set('user_id', $user->id());
$this->entities[0]->save();
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '1', 'id' => $this->entities[0]->id()],
['vid' => '2', 'id' => $this->entities[0]->id()],
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
['vid' => '6', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
// View own $first_bundle + View any $second_bundle.
$user = $this->createUser([
'view own first entity_test_enhanced_with_owner',
'view any second entity_test_enhanced_with_owner',
]);
$this->container->get('current_user')->setAccount($user);
$this->entities[1]->set('user_id', $user->id());
$this->entities[1]->save();
$view = Views::getView('entity_test_enhanced_with_owner_revisions');
$view->execute();
$this->assertIdenticalResultset($view, [
['vid' => '4', 'id' => $this->entities[1]->id()],
['vid' => '5', 'id' => $this->entities[2]->id()],
['vid' => '6', 'id' => $this->entities[2]->id()],
], ['vid' => 'vid']);
}
}

View File

@@ -0,0 +1,216 @@
<?php
namespace Drupal\Tests\entity\Kernel;
use Drupal\entity_module_test\Entity\EnhancedEntity;
use Drupal\KernelTests\KernelTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\Request;
/**
* @group entity
*/
class RevisionBasicUITest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['entity_module_test', 'system', 'user', 'entity'];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test_enhanced');
$this->installSchema('system', 'sequences');
$this->installConfig(['system', 'user']);
$this->container->get('router.builder')->rebuild();
// Create a test user so that the mock requests performed below have a valid
// current user context.
$user = User::create([
// Make sure not to create user 1 which would bypass any access
// restrictions.
'uid' => 2,
'name' => 'Test user',
]);
$user->save();
$this->container->get('account_switcher')->switchTo($user);
}
/**
* Tests the revision history controller.
*/
public function testRevisionHistory() {
$entity = EnhancedEntity::create([
'name' => 'rev 1',
'type' => 'default',
]);
$entity->save();
$revision = clone $entity;
$revision->name->value = 'rev 2';
$revision->setNewRevision(TRUE);
$revision->isDefaultRevision(FALSE);
$revision->save();
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
$http_kernel = $this->container->get('http_kernel');
$request = Request::create($revision->toUrl('version-history')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(403, $response->getStatusCode());
$role_admin = Role::create([
'id' => 'test_role_admin',
'label' => 'Test role admin',
]);
$role_admin->grantPermission('administer entity_test_enhanced');
$role_admin->save();
$role = Role::create([
'id' => 'test_role',
'label' => 'Test role',
]);
$role->grantPermission('view all entity_test_enhanced revisions');
$role->grantPermission('administer entity_test_enhanced');
$role->save();
$user_admin = User::create([
'name' => 'Test administrator',
]);
$user_admin->addRole($role_admin->id());
$user_admin->save();
$this->container->get('account_switcher')->switchTo($user_admin);
$request = Request::create($revision->toUrl('version-history')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(200, $response->getStatusCode());
$user = User::create([
'name' => 'Test editor',
]);
$user->addRole($role->id());
$user->save();
$this->container->get('account_switcher')->switchTo($user);
$request = Request::create($revision->toUrl('version-history')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(200, $response->getStatusCode());
// This ensures that the default revision is still the first revision.
$this->assertTrue(strpos($response->getContent(), 'entity_test_enhanced/1/revisions/2/view') !== FALSE);
$this->assertTrue(strpos($response->getContent(), 'entity_test_enhanced/1') !== FALSE);
// Publish a new revision.
$revision = clone $entity;
$revision->name->value = 'rev 3';
$revision->setNewRevision(TRUE);
$revision->isDefaultRevision(TRUE);
$revision->save();
$request = Request::create($revision->toUrl('version-history')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(200, $response->getStatusCode());
// The first revision row should now include a revert link.
$this->assertTrue(strpos($response->getContent(), 'entity_test_enhanced/1/revisions/1/revert') !== FALSE);
}
public function testRevisionView() {
$entity = EnhancedEntity::create([
'name' => 'rev 1',
'type' => 'default',
]);
$entity->save();
$revision = clone $entity;
$revision->name->value = 'rev 2';
$revision->setNewRevision(TRUE);
$revision->isDefaultRevision(FALSE);
$revision->save();
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
$http_kernel = $this->container->get('http_kernel');
$request = Request::create($revision->toUrl('revision')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(403, $response->getStatusCode());
$role_admin = Role::create([
'id' => 'test_role_admin',
'label' => 'Test role admin',
]);
$role_admin->grantPermission('administer entity_test_enhanced');
$role_admin->save();
$role = Role::create([
'id' => 'test_role',
'label' => 'Test role',
]);
$role->grantPermission('view all entity_test_enhanced revisions');
$role->grantPermission('administer entity_test_enhanced');
$role->save();
$user_admin = User::create([
'name' => 'Test administrator',
]);
$user_admin->addRole($role_admin->id());
$user_admin->save();
$this->container->get('account_switcher')->switchTo($user_admin);
$request = Request::create($revision->toUrl('version-history')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(200, $response->getStatusCode());
$user = User::create([
'name' => 'Test editor',
]);
$user->addRole($role->id());
$user->save();
$this->container->get('account_switcher')->switchTo($user);
$request = Request::create($revision->toUrl('revision')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertStringNotContainsString('rev 1', $response->getContent());
$this->assertStringContainsString('rev 2', $response->getContent());
}
public function testRevisionRevert() {
$entity = EnhancedEntity::create([
'name' => 'rev 1',
'type' => 'entity_test_enhance',
]);
$entity->save();
$entity->name->value = 'rev 2';
$entity->setNewRevision(TRUE);
$entity->isDefaultRevision(TRUE);
$entity->save();
$role = Role::create([
'id' => 'test_role',
'label' => 'Test role',
]);
$role->grantPermission('administer entity_test_enhanced');
$role->grantPermission('revert all entity_test_enhanced revisions');
$role->save();
$user = User::create([
'name' => 'Test administrator',
]);
$user->addRole($role->id());
$user->save();
$this->container->get('account_switcher')->switchTo($user);
/** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
$http_kernel = $this->container->get('http_kernel');
$request = Request::create($entity->toUrl('revision-revert-form')->toString());
$response = $http_kernel->handle($request);
$this->assertEquals(200, $response->getStatusCode());
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace Drupal\Tests\entity\Unit;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity\BundleEntityAccessControlHandler;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\entity\BundleEntityAccessControlHandler
* @group entity
*/
class BundleEntityAccessControlHandlerTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
$module_handler->invokeAll(Argument::any(), Argument::any())->willReturn([]);
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
$cache_contexts_manager->assertValidTokens(Argument::any())->willReturn(TRUE);
$container = new ContainerBuilder();
$container->set('module_handler', $module_handler->reveal());
$container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
\Drupal::setContainer($container);
}
/**
* @covers ::checkAccess
*
* @dataProvider accessProvider
*/
public function testAccess($operation, $uid, $permission, $allowed) {
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
$entity_type->id()->willReturn('green_entity_bundle');
$entity_type->getBundleOf()->willReturn('green_entity');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type = $entity_type->reveal();
$entity = $this->prophesize(ConfigEntityInterface::class);
$entity->getEntityType()->willReturn($entity_type);
$entity->getEntityTypeId()->willReturn('green_entity_bundle');
$entity->id()->willReturn('default');
$entity->uuid()->willReturn('fake uuid');
$entity->language()->willReturn(new Language(['id' => LanguageInterface::LANGCODE_NOT_SPECIFIED]));
$entity = $entity->reveal();
$account = $this->buildMockUser($uid, $permission)->reveal();
$handler = new BundleEntityAccessControlHandler($entity->getEntityType());
$handler->setStringTranslation($this->getStringTranslationStub());
$result = $handler->access($entity, $operation, $account);
$this->assertEquals($allowed, $result);
}
/**
* Data provider for testAccess().
*
* @return array
* A list of testAccess method arguments.
*/
public static function accessProvider() {
// User with no access.
$data[] = ['view label', 1, 'access content', FALSE];
// Permissions which grant "view label" access.
$permissions = [
'administer green_entity',
'view green_entity',
'view default green_entity',
'view own green_entity',
'view any green_entity',
'view own default green_entity',
'view any default green_entity',
];
foreach ($permissions as $index => $permission) {
$data[] = ['view label', 10 + $index, $permission, TRUE];
}
return $data;
}
/**
* Builds a mock user.
*
* @param int $uid
* The user ID.
* @param string $permission
* The permission to grant.
*
* @return \Prophecy\Prophecy\ObjectProphecy
* The user mock.
*/
protected function buildMockUser($uid, $permission) {
$account = $this->prophesize(AccountInterface::class);
$account->id()->willReturn($uid);
$account->hasPermission($permission)->willReturn(TRUE);
$account->hasPermission(Argument::any())->willReturn(FALSE);
return $account;
}
}

View File

@@ -0,0 +1,261 @@
<?php
namespace Drupal\Tests\entity\Unit;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity\EntityAccessControlHandler;
use Drupal\entity\EntityPermissionProvider;
use Drupal\Tests\UnitTestCase;
use Drupal\user\EntityOwnerInterface;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\entity\EntityAccessControlHandler
* @group entity
*/
class EntityAccessControlHandlerTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
$module_handler->invokeAll(Argument::any(), Argument::any())->willReturn([]);
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
$cache_contexts_manager->assertValidTokens(Argument::any())->willReturn(TRUE);
$container = new ContainerBuilder();
$container->set('module_handler', $module_handler->reveal());
$container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
\Drupal::setContainer($container);
}
/**
* @covers ::checkAccess
* @covers ::checkEntityPermissions
* @covers ::checkEntityOwnerPermissions
* @covers ::checkCreateAccess
*
* @dataProvider accessProvider
*/
public function testAccess(array $entity_mock_args, $operation, array $user_mock_args, $allowed, $cache_contexts) {
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
$entity_type->id()->willReturn('green_entity');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
$entity_type->getHandlerClass('permission_provider')->willReturn(EntityPermissionProvider::class);
$entity = $this->buildMockEntity(...array_merge([$entity_type->reveal()], $entity_mock_args))->reveal();
$account = $this->buildMockUser(...$user_mock_args)->reveal();
$handler = new EntityAccessControlHandler($entity->getEntityType());
$handler->setStringTranslation($this->getStringTranslationStub());
$result = $handler->access($entity, $operation, $account, TRUE);
$this->assertEquals($allowed, $result->isAllowed());
$this->assertEqualsCanonicalizing($cache_contexts, $result->getCacheContexts());
}
/**
* @covers ::checkCreateAccess
*
* @dataProvider createAccessProvider
*/
public function testCreateAccess($bundle, array $account_mock_args, $allowed, $cache_contexts) {
$entity_type = $this->prophesize(ContentEntityTypeInterface::class);
$entity_type->id()->willReturn('green_entity');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
$entity_type->getHandlerClass('permission_provider')->willReturn(EntityPermissionProvider::class);
$account = $this->buildMockUser(...$account_mock_args)->reveal();
$handler = new EntityAccessControlHandler($entity_type->reveal());
$handler->setStringTranslation($this->getStringTranslationStub());
$result = $handler->createAccess($bundle, $account, [], TRUE);
$this->assertEquals($allowed, $result->isAllowed());
$this->assertEquals($cache_contexts, $result->getCacheContexts());
}
/**
* Data provider for testAccess().
*
* @return array
* A list of testAccess method arguments.
*/
public static function accessProvider() {
$entity_mock_args = [6];
$data = [];
// Admin permission.
$admin_user_mock_args = [5, 'administer green_entity'];
$data['admin user, view'] = [$entity_mock_args, 'view', $admin_user_mock_args, TRUE, ['user.permissions']];
$data['admin user, update'] = [$entity_mock_args, 'update', $admin_user_mock_args, TRUE, ['user.permissions']];
$data['admin user, duplicate'] = [$entity_mock_args, 'duplicate', $admin_user_mock_args, TRUE, ['user.permissions']];
$data['admin user, delete'] = [$entity_mock_args, 'delete', $admin_user_mock_args, TRUE, ['user.permissions']];
// View, update, duplicate, delete permissions, entity without an owner.
$second_entity_mock_args = [];
foreach (['view', 'update', 'duplicate', 'delete'] as $operation) {
$first_user_mock_args = [6, $operation . ' green_entity'];
$second_user_mock_args = [7, 'access content'];
$data["first user, $operation, entity without owner"] = [$second_entity_mock_args, $operation, $first_user_mock_args, TRUE, ['user.permissions']];
$data["second user, $operation, entity without owner"] = [$second_entity_mock_args, $operation, $second_user_mock_args, FALSE, ['user.permissions']];
}
// Update, duplicate, and delete permissions.
foreach (['update', 'duplicate', 'delete'] as $operation) {
// Owner, non-owner, user with "any" permission.
$first_user_mock_args = [6, $operation . ' own green_entity'];
$second_user_mock_args = [7, $operation . ' own green_entity'];
$third_user_mock_args = [8, $operation . ' any green_entity'];
$data["first user, $operation, entity with owner"] = [$entity_mock_args, $operation, $first_user_mock_args, TRUE, ['user', 'user.permissions']];
$data["second user, $operation, entity with owner"] = [$entity_mock_args, $operation, $second_user_mock_args, FALSE, ['user', 'user.permissions']];
$data["third user, $operation, entity with owner"] = [$entity_mock_args, $operation, $third_user_mock_args, TRUE, ['user.permissions']];
}
// View permissions.
$first_user_mock_args = [9, 'view green_entity'];
$second_user_mock_args = [10, 'view first green_entity'];
$third_user_mock_args = [14, 'view own unpublished green_entity'];
$fourth_user_mock_args = [14, 'access content'];
$first_entity_mock_args = [1, 'first'];
$second_entity_mock_args = [1, 'second'];
$third_entity_mock_args = [14, 'first', FALSE];
// The first user can view the two published entities.
$data['first user, view, first entity'] = [$first_entity_mock_args, 'view', $first_user_mock_args, TRUE, ['user.permissions']];
$data['first user, view, second entity'] = [$second_entity_mock_args, 'view', $first_user_mock_args, TRUE, ['user.permissions']];
$data['first user, view, third entity'] = [$third_entity_mock_args, 'view', $first_user_mock_args, FALSE, ['user']];
// The second user can only view published entities of bundle "first".
$data['second user, view, first entity'] = [$first_entity_mock_args, 'view', $second_user_mock_args, TRUE, ['user.permissions']];
$data['second user, view, second entity'] = [$second_entity_mock_args, 'view', $second_user_mock_args, FALSE, ['user.permissions']];
$data['second user, view, third entity'] = [$third_entity_mock_args, 'view', $second_user_mock_args, FALSE, ['user']];
// The third user can view their own unpublished entity.
$data['third user, view, first entity'] = [$first_entity_mock_args, 'view', $third_user_mock_args, FALSE, ['user.permissions']];
$data['third user, view, second entity'] = [$second_entity_mock_args, 'view', $third_user_mock_args, FALSE, ['user.permissions']];
$data['third user, view, third entity'] = [$third_entity_mock_args, 'view', $third_user_mock_args, TRUE, ['user', 'user.permissions']];
// The fourth user can't view anything.
$data['fourth user, view, first entity'] = [$first_entity_mock_args, 'view', $fourth_user_mock_args, FALSE, ['user.permissions']];
$data['fourth user, view, second entity'] = [$second_entity_mock_args, 'view', $fourth_user_mock_args, FALSE, ['user.permissions']];
$data['fourth user, view, third entity'] = [$third_entity_mock_args, 'view', $fourth_user_mock_args, FALSE, ['user', 'user.permissions']];
return $data;
}
/**
* Data provider for testCreateAccess().
*
* @return array
* A list of testCreateAccess method arguments.
*/
public static function createAccessProvider() {
$data = [];
// User with the admin permission.
$account_mock_args = ['6', 'administer green_entity'];
$data['admin user'] = [NULL, $account_mock_args, TRUE, ['user.permissions']];
// Ordinary user.
$account_mock_args = ['6', 'create green_entity'];
$data['regular user'] = [NULL, $account_mock_args, TRUE, ['user.permissions']];
// Ordinary user, entity with a bundle.
$account_mock_args = ['6', 'create first_bundle green_entity'];
$data['regular user, entity with bundle'] = ['first_bundle', $account_mock_args, TRUE, ['user.permissions']];
// User with no permissions.
$account_mock_args = ['6', 'access content'];
$data['user without permission'] = [NULL, $account_mock_args, FALSE, ['user.permissions']];
return $data;
}
/**
* Builds a mock entity.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
* @param string $owner_id
* The owner ID.
* @param string $bundle
* The bundle.
* @param bool $published
* Whether the entity is published.
*
* @return \Prophecy\Prophecy\ObjectProphecy
* The entity mock.
*/
protected function buildMockEntity(EntityTypeInterface $entity_type, $owner_id = NULL, $bundle = NULL, $published = NULL) {
$langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
$entity = $this->prophesize(ContentEntityInterface::class);
if (isset($published)) {
$entity->willImplement(EntityPublishedInterface::class);
}
if ($owner_id) {
$entity->willImplement(EntityOwnerInterface::class);
}
if (isset($published)) {
$entity->isPublished()->willReturn($published);
}
if ($owner_id) {
$entity->getOwnerId()->willReturn($owner_id);
}
$entity->bundle()->willReturn($bundle ?: $entity_type->id());
$entity->isNew()->willReturn(FALSE);
$entity->uuid()->willReturn('fake uuid');
$entity->id()->willReturn('fake id');
$entity->getRevisionId()->willReturn(NULL);
$entity->language()->willReturn(new Language(['id' => $langcode]));
$entity->getEntityTypeId()->willReturn($entity_type->id());
$entity->getEntityType()->willReturn($entity_type);
$entity->getCacheContexts()->willReturn([]);
$entity->getCacheTags()->willReturn([]);
$entity->getCacheMaxAge()->willReturn(Cache::PERMANENT);
$entity->isDefaultRevision()->willReturn(TRUE);
return $entity;
}
/**
* Builds a mock user.
*
* @param int $uid
* The user ID.
* @param string $permission
* The permission to grant.
*
* @return \Prophecy\Prophecy\ObjectProphecy
* The user mock.
*/
protected function buildMockUser($uid, $permission) {
$account = $this->prophesize(AccountInterface::class);
$account->id()->willReturn($uid);
$account->hasPermission($permission)->willReturn(TRUE);
$account->hasPermission(Argument::any())->willReturn(FALSE);
return $account;
}
}

View File

@@ -0,0 +1,207 @@
<?php
namespace Drupal\Tests\entity\Unit;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\entity\EntityPermissionProvider;
use Drupal\Tests\UnitTestCase;
use Drupal\user\EntityOwnerInterface;
use Prophecy\Prophet;
/**
* @coversDefaultClass \Drupal\entity\EntityPermissionProvider
* @group entity
*/
class EntityPermissionProviderTest extends UnitTestCase {
/**
* The entity permission provider.
*
* @var \Drupal\entity\EntityPermissionProviderInterface
*/
protected $permissionProvider;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$entity_type_bundle_info = $this->prophesize(EntityTypeBundleInfoInterface::class);
$entity_type_bundle_info->getBundleInfo('white_entity')->willReturn([
'first' => ['label' => 'First'],
'second' => ['label' => 'Second'],
]);
$entity_type_bundle_info->getBundleInfo('black_entity')->willReturn([
'third' => ['label' => 'Third'],
]);
$entity_type_bundle_info->getBundleInfo('pink_entity')->willReturn([
'third' => ['label' => 'Third'],
]);
$this->permissionProvider = new EntityPermissionProvider($entity_type_bundle_info->reveal());
$this->permissionProvider->setStringTranslation($this->getStringTranslationStub());
}
/**
* @covers ::buildPermissions
*
* @dataProvider entityTypeProvider
*/
public function testBuildPermissions(EntityTypeInterface $entity_type, array $expected_permissions) {
$permissions = $this->permissionProvider->buildPermissions($entity_type);
$this->assertEquals(array_keys($expected_permissions), array_keys($permissions));
foreach ($permissions as $name => $permission) {
$this->assertEquals('entity_module_test', $permission['provider']);
$this->assertEquals($expected_permissions[$name], $permission['title']);
}
}
/**
* Data provider for testBuildPermissions().
*
* @return array
* A list of testBuildPermissions method arguments.
*/
public static function entityTypeProvider() {
$data = [];
// Content entity type.
$prophet = new Prophet();
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('green_entity');
$entity_type->getSingularLabel()->willReturn('green entity');
$entity_type->getPluralLabel()->willReturn('green entities');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(FALSE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('entity_type');
$expected_permissions = [
'administer green_entity' => 'Administer green entities',
'create green_entity' => 'Create green entities',
'update green_entity' => 'Update green entities',
'duplicate green_entity' => 'Duplicate green entities',
'delete green_entity' => 'Delete green entities',
'view green_entity' => 'View green entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with owner.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('blue_entity');
$entity_type->getSingularLabel()->willReturn('blue entity');
$entity_type->getPluralLabel()->willReturn('blue entities');
$entity_type->getAdminPermission()->willReturn('administer blue_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('entity_type');
$expected_permissions = [
'administer blue_entity' => 'Administer blue entities',
'access blue_entity overview' => 'Access the blue entities overview page',
'create blue_entity' => 'Create blue entities',
'update any blue_entity' => 'Update any blue entity',
'update own blue_entity' => 'Update own blue entities',
'duplicate any blue_entity' => 'Duplicate any blue entity',
'duplicate own blue_entity' => 'Duplicate own blue entities',
'delete any blue_entity' => 'Delete any blue entity',
'delete own blue_entity' => 'Delete own blue entities',
'view blue_entity' => 'View blue entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with bundles.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('white_entity');
$entity_type->getSingularLabel()->willReturn('white entity');
$entity_type->getPluralLabel()->willReturn('white entities');
$entity_type->getAdminPermission()->willReturn('administer white_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('bundle');
$expected_permissions = [
'administer white_entity' => 'Administer white entities',
'access white_entity overview' => 'Access the white entities overview page',
'create first white_entity' => 'First: Create white entities',
'update first white_entity' => 'First: Update white entities',
'duplicate first white_entity' => 'First: Duplicate white entities',
'delete first white_entity' => 'First: Delete white entities',
'create second white_entity' => 'Second: Create white entities',
'update second white_entity' => 'Second: Update white entities',
'duplicate second white_entity' => 'Second: Duplicate white entities',
'delete second white_entity' => 'Second: Delete white entities',
'view white_entity' => 'View white entities',
'view first white_entity' => 'First: View white entities',
'view second white_entity' => 'Second: View white entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with bundles and owner.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('black_entity');
$entity_type->getSingularLabel()->willReturn('black entity');
$entity_type->getPluralLabel()->willReturn('black entities');
$entity_type->getAdminPermission()->willReturn('administer black_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('bundle');
$expected_permissions = [
'administer black_entity' => 'Administer black entities',
'access black_entity overview' => 'Access the black entities overview page',
'create third black_entity' => 'Third: Create black entities',
'update any third black_entity' => 'Third: Update any black entity',
'update own third black_entity' => 'Third: Update own black entities',
'duplicate any third black_entity' => 'Third: Duplicate any black entity',
'duplicate own third black_entity' => 'Third: Duplicate own black entities',
'delete any third black_entity' => 'Third: Delete any black entity',
'delete own third black_entity' => 'Third: Delete own black entities',
'view black_entity' => 'View black entities',
'view third black_entity' => 'Third: View black entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with bundles and owner and entity published.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('pink_entity');
$entity_type->getSingularLabel()->willReturn('pink entity');
$entity_type->getPluralLabel()->willReturn('pink entities');
$entity_type->getAdminPermission()->willReturn('administer pink_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(TRUE);
$entity_type->getPermissionGranularity()->willReturn('bundle');
$expected_permissions = [
'administer pink_entity' => 'Administer pink entities',
'access pink_entity overview' => 'Access the pink entities overview page',
'view own unpublished pink_entity' => 'View own unpublished pink entities',
'create third pink_entity' => 'Third: Create pink entities',
'update any third pink_entity' => 'Third: Update any pink entity',
'update own third pink_entity' => 'Third: Update own pink entities',
'duplicate any third pink_entity' => 'Third: Duplicate any pink entity',
'duplicate own third pink_entity' => 'Third: Duplicate own pink entities',
'delete any third pink_entity' => 'Third: Delete any pink entity',
'delete own third pink_entity' => 'Third: Delete own pink entities',
'view pink_entity' => 'View pink entities',
'view third pink_entity' => 'Third: View pink entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
return $data;
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Drupal\Tests\entity\Unit\QueryAccess;
use Drupal\entity\QueryAccess\Condition;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\entity\QueryAccess\Condition
* @group entity
*/
class ConditionTest extends UnitTestCase {
/**
* ::covers __construct.
*/
public function testInvalidOperator() {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Unrecognized operator "INVALID".');
new Condition('uid', '1', 'INVALID');
}
/**
* ::covers getField
* ::covers getValue
* ::covers getOperator
* ::covers __toString.
*/
public function testGetters() {
$condition = new Condition('uid', '2');
$this->assertEquals('uid', $condition->getField());
$this->assertEquals('2', $condition->getValue());
$this->assertEquals('=', $condition->getOperator());
$this->assertEquals("uid = '2'", $condition->__toString());
$condition = new Condition('type', ['article', 'page']);
$this->assertEquals('type', $condition->getField());
$this->assertEquals(['article', 'page'], $condition->getValue());
$this->assertEquals('IN', $condition->getOperator());
$this->assertEquals("type IN ['article', 'page']", $condition->__toString());
$condition = new Condition('title', NULL, 'IS NULL');
$this->assertEquals('title', $condition->getField());
$this->assertEquals(NULL, $condition->getValue());
$this->assertEquals('IS NULL', $condition->getOperator());
$this->assertEquals("title IS NULL", $condition->__toString());
}
}

View File

@@ -0,0 +1,258 @@
<?php
namespace Drupal\Tests\entity\Unit;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\entity\UncacheableEntityAccessControlHandler;
use Drupal\entity\UncacheableEntityPermissionProvider;
use Drupal\Tests\UnitTestCase;
use Drupal\user\EntityOwnerInterface;
use Prophecy\Argument;
use Prophecy\Prophet;
/**
* @coversDefaultClass \Drupal\entity\UncacheableEntityAccessControlHandler
* @group entity
*/
class UncacheableEntityAccessControlHandlerTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$module_handler = $this->prophesize(ModuleHandlerInterface::class);
$module_handler->invokeAll(Argument::any(), Argument::any())->willReturn([]);
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
$cache_contexts_manager->assertValidTokens(Argument::any())->willReturn(TRUE);
$container = new ContainerBuilder();
$container->set('module_handler', $module_handler->reveal());
$container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
\Drupal::setContainer($container);
}
/**
* @covers ::checkAccess
* @covers ::checkEntityPermissions
* @covers ::checkEntityOwnerPermissions
* @covers ::checkCreateAccess
*
* @dataProvider accessProvider
*/
public function testAccess(EntityInterface $entity, $operation, $account, $allowed) {
$handler = new UncacheableEntityAccessControlHandler($entity->getEntityType());
$handler->setStringTranslation($this->getStringTranslationStub());
$result = $handler->access($entity, $operation, $account);
$this->assertEquals($allowed, $result);
}
/**
* @covers ::checkCreateAccess
*
* @dataProvider createAccessProvider
*/
public function testCreateAccess(EntityTypeInterface $entity_type, $bundle, $account, $allowed) {
$handler = new UncacheableEntityAccessControlHandler($entity_type);
$handler->setStringTranslation($this->getStringTranslationStub());
$result = $handler->createAccess($bundle, $account);
$this->assertEquals($allowed, $result);
}
/**
* Data provider for testAccess().
*
* @return array
* A list of testAccess method arguments.
*/
public static function accessProvider() {
$prophet = new Prophet();
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->id()->willReturn('green_entity');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
$entity_type->getHandlerClass('permission_provider')->willReturn(UncacheableEntityPermissionProvider::class);
$entity = static::buildMockEntity($entity_type->reveal(), 6);
$data = [];
// Admin permission.
$admin_user = static::buildMockUser(5, 'administer green_entity');
$data[] = [$entity->reveal(), 'view', $admin_user->reveal(), TRUE];
$data[] = [$entity->reveal(), 'update', $admin_user->reveal(), TRUE];
$data[] = [$entity->reveal(), 'duplicate', $admin_user->reveal(), TRUE];
$data[] = [$entity->reveal(), 'delete', $admin_user->reveal(), TRUE];
// View, update, duplicate, delete permissions, entity without an owner.
$second_entity = static::buildMockEntity($entity_type->reveal());
foreach (['view', 'update', 'duplicate', 'delete'] as $operation) {
$first_user = static::buildMockUser(6, $operation . ' green_entity');
$second_user = static::buildMockUser(7, 'access content');
$data[] = [$second_entity->reveal(), $operation, $first_user->reveal(), TRUE];
$data[] = [$second_entity->reveal(), $operation, $second_user->reveal(), FALSE];
}
// View, update, duplicate, delete permissions.
foreach (['view', 'update', 'duplicate', 'delete'] as $operation) {
// Owner, non-owner, user with "any" permission.
$first_user = static::buildMockUser(6, $operation . ' own green_entity');
$second_user = static::buildMockUser(7, $operation . ' own green_entity');
$third_user = static::buildMockUser(8, $operation . ' any green_entity');
$data[] = [$entity->reveal(), $operation, $first_user->reveal(), TRUE];
$data[] = [$entity->reveal(), $operation, $second_user->reveal(), FALSE];
$data[] = [$entity->reveal(), $operation, $third_user->reveal(), TRUE];
}
// Per bundle and unpublished view permissions.
$first_user = static::buildMockUser(11, 'view any first green_entity');
$second_user = static::buildMockUser(12, 'view own first green_entity');
$third_user = static::buildMockUser(13, 'view own unpublished green_entity');
$first_entity = static::buildMockEntity($entity_type->reveal(), 9999, 'first');
$second_entity = static::buildMockEntity($entity_type->reveal(), 12, 'first');
$third_entity = static::buildMockEntity($entity_type->reveal(), 9999, 'second');
$fourth_entity = static::buildMockEntity($entity_type->reveal(), 10, 'second');
$fifth_entity = static::buildMockEntity($entity_type->reveal(), 13, 'first', FALSE);
// The first user can view the two entities of bundle "first".
$data[] = [$first_entity->reveal(), 'view', $first_user->reveal(), TRUE];
$data[] = [$second_entity->reveal(), 'view', $first_user->reveal(), TRUE];
$data[] = [$third_entity->reveal(), 'view', $first_user->reveal(), FALSE];
$data[] = [$fourth_entity->reveal(), 'view', $first_user->reveal(), FALSE];
$data[] = [$fifth_entity->reveal(), 'view', $first_user->reveal(), FALSE];
// The second user can view their own entity of bundle "first".
$data[] = [$first_entity->reveal(), 'view', $second_user->reveal(), FALSE];
$data[] = [$second_entity->reveal(), 'view', $second_user->reveal(), TRUE];
$data[] = [$third_entity->reveal(), 'view', $second_user->reveal(), FALSE];
$data[] = [$fourth_entity->reveal(), 'view', $second_user->reveal(), FALSE];
$data[] = [$fourth_entity->reveal(), 'view', $second_user->reveal(), FALSE];
$data[] = [$fifth_entity->reveal(), 'view', $second_user->reveal(), FALSE];
// The third user can only view their own unpublished entity.
$data[] = [$first_entity->reveal(), 'view', $third_user->reveal(), FALSE];
$data[] = [$second_entity->reveal(), 'view', $third_user->reveal(), FALSE];
$data[] = [$third_entity->reveal(), 'view', $third_user->reveal(), FALSE];
$data[] = [$fourth_entity->reveal(), 'view', $third_user->reveal(), FALSE];
$data[] = [$fourth_entity->reveal(), 'view', $third_user->reveal(), FALSE];
$data[] = [$fifth_entity->reveal(), 'view', $third_user->reveal(), TRUE];
return $data;
}
/**
* Data provider for testCreateAccess().
*
* @return array
* A list of testCreateAccess method arguments.
*/
public static function createAccessProvider() {
$data = [];
$prophet = new Prophet();
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->id()->willReturn('green_entity');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type->hasHandlerClass('permission_provider')->willReturn(TRUE);
$entity_type->getHandlerClass('permission_provider')->willReturn(UncacheableEntityPermissionProvider::class);
// User with the admin permission.
$account = static::buildMockUser('6', 'administer green_entity');
$data[] = [$entity_type->reveal(), NULL, $account->reveal(), TRUE];
// Ordinary user.
$account = static::buildMockUser('6', 'create green_entity');
$data[] = [$entity_type->reveal(), NULL, $account->reveal(), TRUE];
// Ordinary user, entity with a bundle.
$account = static::buildMockUser('6', 'create first_bundle green_entity');
$data[] = [$entity_type->reveal(), 'first_bundle', $account->reveal(), TRUE];
// User with no permissions.
$account = static::buildMockUser('6', 'access content');
$data[] = [$entity_type->reveal(), NULL, $account->reveal(), FALSE];
return $data;
}
/**
* Builds a mock entity.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
* @param string $owner_id
* The owner ID.
* @param string $bundle
* The bundle.
* @param bool $published
* Whether the entity is published.
*
* @return \Prophecy\Prophecy\ObjectProphecy
* The entity mock.
*/
protected static function buildMockEntity(EntityTypeInterface $entity_type, $owner_id = NULL, $bundle = NULL, $published = NULL) {
$langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
$prophet = new Prophet();
$entity = $prophet->prophesize(ContentEntityInterface::class);
if (isset($published)) {
$entity->willImplement(EntityPublishedInterface::class);
}
if ($owner_id) {
$entity->willImplement(EntityOwnerInterface::class);
}
if (isset($published)) {
$entity->isPublished()->willReturn($published);
}
if ($owner_id) {
$entity->getOwnerId()->willReturn($owner_id);
}
$entity->bundle()->willReturn($bundle ?: $entity_type->id());
$entity->isNew()->willReturn(FALSE);
$entity->uuid()->willReturn('fake uuid');
$entity->id()->willReturn('fake id');
$entity->getRevisionId()->willReturn(NULL);
$entity->language()->willReturn(new Language(['id' => $langcode]));
$entity->getEntityTypeId()->willReturn($entity_type->id());
$entity->getEntityType()->willReturn($entity_type);
$entity->getCacheContexts()->willReturn([]);
$entity->getCacheTags()->willReturn([]);
$entity->getCacheMaxAge()->willReturn(Cache::PERMANENT);
return $entity;
}
/**
* Builds a mock user.
*
* @param int $uid
* The user ID.
* @param string $permission
* The permission to grant.
*
* @return \Prophecy\Prophecy\ObjectProphecy
* The user mock.
*/
protected static function buildMockUser($uid, $permission) {
$prophet = new Prophet();
$account = $prophet->prophesize(AccountInterface::class);
$account->id()->willReturn($uid);
$account->hasPermission($permission)->willReturn(TRUE);
$account->hasPermission(Argument::any())->willReturn(FALSE);
return $account;
}
}

View File

@@ -0,0 +1,211 @@
<?php
namespace Drupal\Tests\entity\Unit;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\entity\UncacheableEntityPermissionProvider;
use Drupal\Tests\UnitTestCase;
use Drupal\user\EntityOwnerInterface;
use Prophecy\Prophet;
/**
* @coversDefaultClass \Drupal\entity\UncacheableEntityPermissionProvider
* @group entity
*/
class UncacheableEntityPermissionProviderTest extends UnitTestCase {
/**
* The entity permission provider.
*
* @var \Drupal\entity\EntityPermissionProviderInterface
*/
protected $permissionProvider;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$entity_type_bundle_info = $this->prophesize(EntityTypeBundleInfoInterface::class);
$entity_type_bundle_info->getBundleInfo('white_entity')->willReturn([
'first' => ['label' => 'First'],
'second' => ['label' => 'Second'],
]);
$entity_type_bundle_info->getBundleInfo('black_entity')->willReturn([
'third' => ['label' => 'Third'],
]);
$entity_type_bundle_info->getBundleInfo('pink_entity')->willReturn([
'third' => ['label' => 'Third'],
]);
$this->permissionProvider = new UncacheableEntityPermissionProvider($entity_type_bundle_info->reveal());
$this->permissionProvider->setStringTranslation($this->getStringTranslationStub());
}
/**
* @covers ::buildPermissions
*
* @dataProvider entityTypeProvider
*/
public function testBuildPermissions(EntityTypeInterface $entity_type, array $expected_permissions) {
$permissions = $this->permissionProvider->buildPermissions($entity_type);
$this->assertEquals(array_keys($expected_permissions), array_keys($permissions));
foreach ($permissions as $name => $permission) {
$this->assertEquals('entity_module_test', $permission['provider']);
$this->assertEquals($expected_permissions[$name], $permission['title']);
}
}
/**
* Data provider for testBuildPermissions().
*
* @return array
* A list of testBuildPermissions method arguments.
*/
public static function entityTypeProvider() {
$data = [];
$prophet = new Prophet();
// Content entity type.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('green_entity');
$entity_type->getSingularLabel()->willReturn('green entity');
$entity_type->getPluralLabel()->willReturn('green entities');
$entity_type->getAdminPermission()->willReturn('administer green_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(FALSE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('entity_type');
$expected_permissions = [
'administer green_entity' => 'Administer green entities',
'create green_entity' => 'Create green entities',
'update green_entity' => 'Update green entities',
'duplicate green_entity' => 'Duplicate green entities',
'delete green_entity' => 'Delete green entities',
'view green_entity' => 'View green entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with owner.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('blue_entity');
$entity_type->getSingularLabel()->willReturn('blue entity');
$entity_type->getPluralLabel()->willReturn('blue entities');
$entity_type->getAdminPermission()->willReturn('administer blue_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('entity_type');
$expected_permissions = [
'administer blue_entity' => 'Administer blue entities',
'access blue_entity overview' => 'Access the blue entities overview page',
'create blue_entity' => 'Create blue entities',
'update any blue_entity' => 'Update any blue entity',
'update own blue_entity' => 'Update own blue entities',
'duplicate any blue_entity' => 'Duplicate any blue entity',
'duplicate own blue_entity' => 'Duplicate own blue entities',
'delete any blue_entity' => 'Delete any blue entity',
'delete own blue_entity' => 'Delete own blue entities',
'view any blue_entity' => 'View any blue entities',
'view own blue_entity' => 'View own blue entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with bundles.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('white_entity');
$entity_type->getSingularLabel()->willReturn('white entity');
$entity_type->getPluralLabel()->willReturn('white entities');
$entity_type->getAdminPermission()->willReturn('administer white_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(FALSE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('bundle');
$expected_permissions = [
'administer white_entity' => 'Administer white entities',
'access white_entity overview' => 'Access the white entities overview page',
'create first white_entity' => 'First: Create white entities',
'update first white_entity' => 'First: Update white entities',
'duplicate first white_entity' => 'First: Duplicate white entities',
'delete first white_entity' => 'First: Delete white entities',
'create second white_entity' => 'Second: Create white entities',
'update second white_entity' => 'Second: Update white entities',
'duplicate second white_entity' => 'Second: Duplicate white entities',
'delete second white_entity' => 'Second: Delete white entities',
'view white_entity' => 'View white entities',
'view first white_entity' => 'First: View white entities',
'view second white_entity' => 'Second: View white entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with bundles and owner.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('black_entity');
$entity_type->getSingularLabel()->willReturn('black entity');
$entity_type->getAdminPermission()->willReturn('administer black_entity');
$entity_type->getPluralLabel()->willReturn('black entities');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(FALSE);
$entity_type->getPermissionGranularity()->willReturn('bundle');
$expected_permissions = [
'administer black_entity' => 'Administer black entities',
'access black_entity overview' => 'Access the black entities overview page',
'create third black_entity' => 'Third: Create black entities',
'update any third black_entity' => 'Third: Update any black entity',
'update own third black_entity' => 'Third: Update own black entities',
'duplicate any third black_entity' => 'Third: Duplicate any black entity',
'duplicate own third black_entity' => 'Third: Duplicate own black entities',
'delete any third black_entity' => 'Third: Delete any black entity',
'delete own third black_entity' => 'Third: Delete own black entities',
'view any black_entity' => 'View any black entities',
'view own black_entity' => 'View own black entities',
'view any third black_entity' => 'Third: View any black entities',
'view own third black_entity' => 'Third: View own black entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
// Content entity type with bundles and owner and entity published.
$entity_type = $prophet->prophesize(ContentEntityTypeInterface::class);
$entity_type->getProvider()->willReturn('entity_module_test');
$entity_type->id()->willReturn('pink_entity');
$entity_type->getSingularLabel()->willReturn('pink entity');
$entity_type->getPluralLabel()->willReturn('pink entities');
$entity_type->getAdminPermission()->willReturn('administer pink_entity');
$entity_type->hasLinkTemplate('collection')->willReturn(TRUE);
$entity_type->hasLinkTemplate('duplicate-form')->willReturn(TRUE);
$entity_type->entityClassImplements(EntityOwnerInterface::class)->willReturn(TRUE);
$entity_type->entityClassImplements(EntityPublishedInterface::class)->willReturn(TRUE);
$entity_type->getPermissionGranularity()->willReturn('bundle');
$expected_permissions = [
'administer pink_entity' => 'Administer pink entities',
'access pink_entity overview' => 'Access the pink entities overview page',
'view own unpublished pink_entity' => 'View own unpublished pink entities',
'create third pink_entity' => 'Third: Create pink entities',
'update any third pink_entity' => 'Third: Update any pink entity',
'update own third pink_entity' => 'Third: Update own pink entities',
'duplicate any third pink_entity' => 'Third: Duplicate any pink entity',
'duplicate own third pink_entity' => 'Third: Duplicate own pink entities',
'delete any third pink_entity' => 'Third: Delete any pink entity',
'delete own third pink_entity' => 'Third: Delete own pink entities',
'view any pink_entity' => 'View any pink entities',
'view own pink_entity' => 'View own pink entities',
'view any third pink_entity' => 'Third: View any pink entities',
'view own third pink_entity' => 'Third: View own pink entities',
];
$data[] = [$entity_type->reveal(), $expected_permissions];
return $data;
}
}