search_api-8.x-1.15/tests/src/Kernel/Processor/ContentAccessTest.php
tests/src/Kernel/Processor/ContentAccessTest.php
<?php namespace Drupal\Tests\search_api\Kernel\Processor; use Drupal\comment\CommentInterface; use Drupal\comment\Entity\Comment; use Drupal\comment\Entity\CommentType; use Drupal\comment\Tests\CommentTestTrait; use Drupal\Core\Database\Database; use Drupal\Core\Session\AnonymousUserSession; use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; use Drupal\node\NodeInterface; use Drupal\Tests\search_api\Kernel\ResultsTrait; use Drupal\user\Entity\Role; use Drupal\user\Entity\User; /** * Tests the "Content access" processor. * * @group search_api * * @see \Drupal\search_api\Plugin\search_api\processor\ContentAccess */ class ContentAccessTest extends ProcessorTestBase { use CommentTestTrait; use ResultsTrait; /** * The nodes created for testing. * * @var \Drupal\node\Entity\Node[] */ protected $nodes; /** * The comments created for testing. * * @var \Drupal\comment\Entity\Comment[] */ protected $comments; /** * {@inheritdoc} */ public function setUp($processor = NULL) { parent::setUp('content_access'); // Create a node type for testing. $type = NodeType::create(['type' => 'page', 'name' => 'page']); $type->save(); // Create anonymous user role. $role = Role::create([ 'id' => 'anonymous', 'label' => 'anonymous', ]); $role->save(); // Insert the anonymous user into the database, as the user table is inner // joined by \Drupal\comment\CommentStorage. User::create([ 'uid' => 0, 'name' => '', ])->save(); // Create a node with attached comment. $values = [ 'status' => NodeInterface::PUBLISHED, 'type' => 'page', 'title' => 'test title', ]; $this->nodes[0] = Node::create($values); $this->nodes[0]->save(); $comment_type = CommentType::create([ 'id' => 'comment', 'target_entity_type_id' => 'node', ]); $comment_type->save(); $this->installConfig(['comment']); $this->addDefaultCommentField('node', 'page'); $comment = Comment::create([ 'status' => CommentInterface::PUBLISHED, 'entity_type' => 'node', 'entity_id' => $this->nodes[0]->id(), 'field_name' => 'comment', 'body' => 'test body', 'comment_type' => $comment_type->id(), ]); $comment->save(); $this->comments[] = $comment; $values = [ 'status' => NodeInterface::PUBLISHED, 'type' => 'page', 'title' => 'some title', ]; $this->nodes[1] = Node::create($values); $this->nodes[1]->save(); $values = [ 'status' => NodeInterface::NOT_PUBLISHED, 'type' => 'page', 'title' => 'other title', ]; $this->nodes[2] = Node::create($values); $this->nodes[2]->save(); // Also index users, to verify that they are unaffected by the processor. $datasources = \Drupal::getContainer() ->get('search_api.plugin_helper') ->createDatasourcePlugins($this->index, [ 'entity:comment', 'entity:node', 'entity:user', ]); $this->index->setDatasources($datasources); $this->index->save(); \Drupal::getContainer()->get('search_api.index_task_manager')->addItemsAll($this->index); $index_storage = \Drupal::entityTypeManager()->getStorage('search_api_index'); $index_storage->resetCache([$this->index->id()]); $this->index = $index_storage->load($this->index->id()); } /** * Tests searching when content is accessible to all. */ public function testQueryAccessAll() { $permissions = ['access content', 'access comments']; user_role_grant_permissions('anonymous', $permissions); $this->index->reindex(); $this->indexItems(); $this->assertEquals(5, $this->index->getTrackerInstance()->getIndexedItemsCount(), '5 items indexed, as expected.'); $query = \Drupal::getContainer() ->get('search_api.query_helper') ->createQuery($this->index); $result = $query->execute(); $expected = [ 'user' => [0], 'comment' => [0], 'node' => [0, 1], ]; $this->assertResults($result, $expected); } /** * Tests searching when only comments are accessible. */ public function testQueryAccessComments() { user_role_grant_permissions('anonymous', ['access comments']); $this->index->reindex(); $this->indexItems(); $this->assertEquals(5, $this->index->getTrackerInstance()->getIndexedItemsCount(), '5 items indexed, as expected.'); $query = \Drupal::getContainer() ->get('search_api.query_helper') ->createQuery($this->index); $result = $query->execute(); $this->assertResults($result, ['user' => [0], 'comment' => [0]]); } /** * Tests searching for own unpublished content. */ public function testQueryAccessOwn() { // Create the user that will be passed into the query. $permissions = [ 'access content', 'access comments', 'view own unpublished content', ]; $authenticated_user = $this->createUser($permissions); $uid = $authenticated_user->id(); $values = [ 'status' => NodeInterface::NOT_PUBLISHED, 'type' => 'page', 'title' => 'foo', 'uid' => $uid, ]; $this->nodes[3] = Node::create($values); $this->nodes[3]->save(); $this->indexItems(); $this->assertEquals(7, $this->index->getTrackerInstance()->getIndexedItemsCount(), '7 items indexed, as expected.'); $query = \Drupal::getContainer() ->get('search_api.query_helper') ->createQuery($this->index); $query->setOption('search_api_access_account', $authenticated_user); $result = $query->execute(); $expected = ['user' => [0, $uid], 'node' => [3]]; $this->assertResults($result, $expected); } /** * Tests building the query when content is accessible based on node grants. */ public function testQueryAccessWithNodeGrants() { // Create the user that will be passed into the query. $permissions = [ 'access content', ]; $authenticated_user = $this->createUser($permissions); Database::getConnection()->insert('node_access') ->fields([ 'nid' => $this->nodes[0]->id(), 'langcode' => $this->nodes[0]->language()->getId(), 'gid' => $authenticated_user->id(), 'realm' => 'search_api_test', 'grant_view' => 1, ]) ->execute(); $this->index->reindex(); $this->indexItems(); $query = \Drupal::getContainer() ->get('search_api.query_helper') ->createQuery($this->index); $query->setOption('search_api_access_account', $authenticated_user); $result = $query->execute(); $expected = [ 'user' => [0, $authenticated_user->id()], 'node' => [0], ]; $this->assertResults($result, $expected); } /** * Tests comment indexing when all users have access to content. */ public function testContentAccessAll() { // Deactivate our custom grant and re-save the grant records. \Drupal::state()->set('search_api_test_add_node_access_grant', FALSE); /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */ $access_control_handler = \Drupal::entityTypeManager() ->getAccessControlHandler('node'); $grants_storage = \Drupal::getContainer()->get('node.grant_storage'); foreach ($this->nodes as $node) { $grants = $access_control_handler->acquireGrants($node); $grants_storage->write($node, $grants); } user_role_grant_permissions('anonymous', ['access content', 'access comments']); $items = []; foreach ($this->comments as $comment) { $items[] = [ 'datasource' => 'entity:comment', 'item' => $comment->getTypedData(), 'item_id' => $comment->id(), 'text' => 'Comment: ' . $comment->id(), ]; } $items = $this->generateItems($items); // Add the processor's field values to the items. foreach ($items as $item) { $this->processor->addFieldValues($item); } // Verify all items were indexed with the same "all" realm grant. $all = ['node_access_all:0']; foreach ($items as $item) { $this->assertEquals($all, $item->getField('node_grants')->getValues()); } // Verify that the anonymous user has exactly that grant. $grants = node_access_grants('view', new AnonymousUserSession()); $this->assertEquals(['all' => [0]], $grants); } /** * Tests comment indexing when hook_node_grants() takes effect. */ public function testContentAccessWithNodeGrants() { $items = []; foreach ($this->comments as $comment) { $items[] = [ 'datasource' => 'entity:comment', 'item' => $comment->getTypedData(), 'item_id' => $comment->id(), 'field_text' => 'Text: &' . $comment->id(), ]; } $items = $this->generateItems($items); // Add the processor's field values to the items. foreach ($items as $item) { $this->processor->addFieldValues($item); } foreach ($items as $item) { $this->assertEquals(['node_access_search_api_test:0'], $item->getField('node_grants')->getValues()); } } /** * Tests that acquiring node grants leads to re-indexing of that node. */ public function testNodeGrantsChange() { $this->index->setOption('index_directly', FALSE)->save(); $this->indexItems(); $remaining = $this->index->getTrackerInstance()->getRemainingItems(); $this->assertEquals([], $remaining, 'All items were indexed.'); /** @var \Drupal\node\NodeAccessControlHandlerInterface $access_control_handler */ $access_control_handler = \Drupal::entityTypeManager() ->getAccessControlHandler('node'); $access_control_handler->acquireGrants($this->nodes[0]); $expected = [ 'entity:comment/' . $this->comments[0]->id() . ':en', 'entity:node/' . $this->nodes[0]->id() . ':en', ]; $remaining = $this->index->getTrackerInstance()->getRemainingItems(); sort($remaining); $this->assertEquals($expected, $remaining, 'The expected items were marked as "changed" when changing node access grants.'); } /** * Tests whether the "search_api_bypass_access" query option is respected. */ public function testQueryAccessBypass() { $this->index->reindex(); $this->indexItems(); $this->assertEquals(5, $this->index->getTrackerInstance()->getIndexedItemsCount(), '5 items indexed, as expected.'); $query = \Drupal::getContainer() ->get('search_api.query_helper') ->createQuery($this->index, ['search_api_bypass_access' => TRUE]); $result = $query->execute(); $expected = [ 'user' => [0], 'comment' => [0], 'node' => [0, 1, 2], ]; $this->assertResults($result, $expected); } /** * Tests whether the property is correctly added by the processor. */ public function testAlterPropertyDefinitions() { // Check for added properties when no datasource is given. $properties = $this->processor->getPropertyDefinitions(NULL); $this->assertTrue(array_key_exists('search_api_node_grants', $properties), 'The Properties where modified with the "search_api_node_grants".'); $this->assertTrue(($properties['search_api_node_grants'] instanceof DataDefinitionInterface), 'The "search_api_node_grants" key contains a valid DataDefinition instance.'); $this->assertEquals('string', $properties['search_api_node_grants']->getDataType(), 'Correct DataType set in the DataDefinition.'); // Verify that there are no properties if a datasource is given. $properties = $this->processor->getPropertyDefinitions($this->index->getDatasource('entity:node')); $this->assertEquals([], $properties, '"search_api_node_grants" property not added when datasource is given.'); } /** * Creates a new user account. * * @param string[] $permissions * The permissions to set for the user. * * @return \Drupal\user\UserInterface * The new user object. */ protected function createUser(array $permissions) { $role = Role::create(['id' => 'role', 'name' => 'Role test']); $role->save(); user_role_grant_permissions($role->id(), $permissions); $values = [ 'uid' => 2, 'name' => 'Test', 'roles' => [$role->id()], ]; $authenticated_user = User::create($values); $authenticated_user->enforceIsNew(); $authenticated_user->save(); return $authenticated_user; } }