entity_change_notifier-8.x-1.0/tests/src/Kernel/EntityPublisherTest.php
tests/src/Kernel/EntityPublisherTest.php
<?php namespace Drupal\Tests\entity_change_notifier\Kernel; use Drupal\entity_change_notifier\Plugin\MessageDestination\MessageDestinationInterface; use Drupal\entity_change_notifier\Plugin\MessageDestination\MessageGenerator; use Drupal\entity_change_notifier\Plugin\MessageDestination\NotifyException; use Drupal\file\Entity\File; use Drupal\KernelTests\KernelTestBase; use Drupal\node\Entity\Node; use Psr\Log\LoggerInterface; use Symfony\Component\Debug\BufferingLogger; /** * Tests publishing entities to destinations. * * The EntityPublisher class is currently very simple, and just wraps calling * individual publishers in a loop. Since unit testing entities is very painful * (they don't support injection), we mark multiple classes as being covered * here. If EntityPublisher becomes more complex, we should split out it's tests * from those that cover Publisher itself. * * @group entity_change_notifier * * @coversDefaultClass Drupal\entity_change_notifier\EntityPublisher */ class EntityPublisherTest extends KernelTestBase { /** * {@inheritdoc} */ protected static $modules = [ 'system', 'field', 'node', 'file', 'text', 'user', 'serialization', 'jsonapi', 'entity_change_notifier', 'entity_change_notifier_test', ]; /** * {@inheritdoc} */ public function setUp() { parent::setUp(); $this->installSchema('node', 'node_access'); $this->installEntitySchema('user'); $this->installEntitySchema('node'); $this->installEntitySchema('file'); $this->installConfig(['node', 'file']); $this->installConfig(['entity_change_notifier_test']); } /** * Test firing of inserts on hook_entity_insert. * * @covers ::notifyMultiple * @covers \Drupal\entity_change_notifier\Entity\Publisher::notify */ public function testNotifyInsert() { $logger = new BufferingLogger(); $this->container->get('logger.factory')->addLogger($logger); $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $logs = $logger->cleanLogs(); $this->assertCount(2, $logs); $this->assertEquals(MessageDestinationInterface::ENTITY_INSERT, $logs[0][2]['%action']); } /** * Test firing of updates on hook_entity_update. * * @covers ::notifyMultiple * @covers \Drupal\entity_change_notifier\Entity\Publisher::notify */ public function testNotifyUpdate() { $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $logger = new BufferingLogger(); $this->container->get('logger.factory')->addLogger($logger); $node->save(); $logs = $logger->cleanLogs(); $this->assertCount(2, $logs); $this->assertEquals(MessageDestinationInterface::ENTITY_UPDATE, $logs[0][2]['%action']); } /** * Test notifying for URI-less entities. * * @covers \Drupal\entity_change_notifier\Entity\Publisher::notify */ public function testNotifyNoUri() { // Turn on notifications for files. /** @var \Drupal\entity_change_notifier\Entity\PublisherInterface $publisher */ $publisher = $this->container->get('entity_type.manager')->getStorage('ecn_publisher')->load('test_publisher'); $publisher->setPublishTypes(['file' => ['file']]); $publisher->save(); $file = File::create([ 'type' => 'file', 'title' => $this->randomString(), 'uri' => 'core/misc/druplicon.png', ]); $file->save(); $logger = new BufferingLogger(); $this->container->get('logger.factory')->addLogger($logger); $file->save(); $logs = $logger->cleanLogs(); $this->assertCount(2, $logs); $this->assertEquals(MessageDestinationInterface::ENTITY_UPDATE, $logs[0][2]['%action']); $this->assertEmpty($logs[1][2]['link']); } /** * Test firing of updates on hook_entity_delete. * * @covers ::notifyMultiple * @covers \Drupal\entity_change_notifier\Entity\Publisher::notify */ public function testNotifyDelete() { $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $logger = new BufferingLogger(); $this->container->get('logger.factory')->addLogger($logger); $node->delete(); $logs = $logger->cleanLogs(); $this->assertCount(2, $logs); $this->assertEquals(MessageDestinationInterface::ENTITY_DELETE, $logs[0][2]['%action']); } /** * Test queuing retry on failure. * * @covers ::notifyMultiple * @covers ::logRetry * @covers ::watchdogException * @covers \Drupal\entity_change_notifier\Entity\Publisher::notify * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::__construct * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::fromNotifyException * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::fromNotifyException * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::getExpires * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::getData * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::getMessageDestinationEntityId */ public function testQueueRetry() { /** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject $logger */ $logger = $this->getMockBuilder(LoggerInterface::class) ->disableOriginalConstructor() ->getMock(); $logger->expects($this->any())->method('error')->willReturn(NULL); $logger->expects($this->any())->method('warning')->willReturn(NULL); $logger->expects($this->at(0))->method('log')->willThrowException(new \Exception('logging error')); $logger->expects($this->at(1))->method('log')->willReturn(TRUE); $this->container->get('logger.factory')->addLogger($logger); $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $queue = \Drupal::queue('entity_change_notifier_retry'); $size = (int) $queue->numberOfItems(); $this->assertSame(1, $size); $item = $queue->claimItem(); /** @var \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem $failedItem */ $failedItem = $item->data; $this->assertEquals($this->container->get('datetime.time')->getRequestTime() + 86400, $failedItem->getExpires()); $this->assertEquals('test_destination', $failedItem->getMessageDestinationEntityId()); $expected = [ '%action' => 'insert', '%uri' => 'http://localhost/jsonapi/node/ecn_test/' . $node->uuid(), '%entity_id' => $node->id(), '%entity_uuid' => $node->uuid(), '%entity_type' => 'node', '%bundle' => 'ecn_test', 'link' => '<a href="http://localhost/jsonapi/node/ecn_test/' . $node->uuid() . '">View</a>', 'action' => 'insert', 'uri' => 'http://localhost/jsonapi/node/ecn_test/' . $node->uuid(), 'entity_id' => $node->id(), 'entity_uuid' => $node->uuid(), 'entity_type' => 'node', 'bundle' => 'ecn_test', ]; $data = $failedItem->getData(); $data['link'] = (string) $data['link']; $this->assertEquals($expected, $data); } /** * Test queuing retry for URL-less entities. * * @covers ::logRetry */ public function testQueueRetryNoCanonical() { $logger = new BufferingLogger(); $this->container->get('logger.factory')->addLogger($logger); $file = File::create([ 'type' => 'file', 'title' => $this->randomString(), 'uri' => 'core/misc/druplicon.png', ]); $file->save(); $publisher = $this->container->get('entity_change_notifier.entity_publisher'); /** @var \Drupal\entity_change_notifier\Entity\DestinationInterface $destination */ $generator = new MessageGenerator($this->container->get('jsonapi.link_manager')); $message = $generator->createMessage(MessageDestinationInterface::ENTITY_INSERT, $file); $exception = new NotifyException($message, new \Exception('Such failure'), 'test_destination'); $destination = $this->container->get('entity_type.manager')->getStorage('ecn_destination')->load('test_destination'); $publisher->logRetry($destination, $exception, $file); $logs = $logger->cleanLogs(); $this->assertEmpty($logs[0][2]['link']); } /** * Test setting a custom retry expiry time. * * @covers ::notifyMultiple * @covers ::logRetry * @covers \Drupal\entity_change_notifier\Entity\Publisher::notify * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::__construct * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::fromNotifyException * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::fromNotifyException * @covers \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem::getExpires */ public function testSetQueueRetry() { /** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject $logger */ $logger = $this->getMockBuilder(LoggerInterface::class) ->disableOriginalConstructor() ->getMock(); $logger->expects($this->any())->method('error')->willReturn(NULL); $logger->expects($this->any())->method('warning')->willReturn(NULL); $logger->expects($this->at(0))->method('log')->willThrowException(new \Exception('logging error')); $logger->expects($this->at(1))->method('log')->willReturn(TRUE); $this->container->get('logger.factory')->addLogger($logger); /** @var \Drupal\entity_change_notifier\Entity\DestinationInterface $destination */ $destination = $this->container->get('entity_type.manager')->getStorage('ecn_destination')->load('test_destination'); // Override the expiry to one second. $destination->setMessageExpiry(1); $destination->save(); $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $queue = \Drupal::queue('entity_change_notifier_retry'); $size = (int) $queue->numberOfItems(); $this->assertSame(1, $size); $item = $queue->claimItem(); /** @var \Drupal\entity_change_notifier\Plugin\QueueWorker\FailedItem $failedItem */ $failedItem = $item->data; $this->assertEquals($this->container->get('datetime.time')->getRequestTime() + 1, $failedItem->getExpires()); } /** * Test that we can retry a failed notification. * * @covers ::retryNotification */ public function testRetryNotification() { $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $message = [ 'action' => MessageDestinationInterface::ENTITY_INSERT, 'uri' => $node->toUrl()->toString(), 'entity_id' => $node->id(), 'entity_uuid' => $node->uuid(), 'entity_type' => 'node', 'bundle' => 'ecn_test', ]; /** @var \Drupal\entity_change_notifier\Entity\DestinationInterface $destination */ $destination = $this->container->get('entity_type.manager')->getStorage('ecn_destination')->load('test_destination'); $logger = new BufferingLogger(); $this->container->get('logger.factory')->addLogger($logger); $publisher = $this->container->get('entity_change_notifier.entity_publisher'); $publisher->retryNotification($destination, $message); $logs = $logger->cleanLogs(); $this->assertCount(1, $logs); } /** * Test that we can retry a failed notification. * * @covers ::retryNotification */ public function testRetryNotificationFails() { $node = Node::create([ 'type' => 'ecn_test', 'title' => $this->randomString(), ]); $node->save(); $message = [ 'action' => MessageDestinationInterface::ENTITY_INSERT, 'uri' => $node->toUrl()->toString(), 'entity_id' => $node->id(), 'entity_uuid' => $node->uuid(), 'entity_type' => 'node', 'bundle' => 'ecn_test', ]; /** @var \Drupal\entity_change_notifier\Entity\DestinationInterface $destination */ $destination = $this->container->get('entity_type.manager')->getStorage('ecn_destination')->load('test_destination'); /** @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject $logger */ $logger = $this->getMockBuilder(LoggerInterface::class) ->disableOriginalConstructor() ->getMock(); $logger->expects($this->at(0))->method('log')->willThrowException(new \Exception('logging error')); $this->container->get('logger.factory')->addLogger($logger); $publisher = $this->container->get('entity_change_notifier.entity_publisher'); $this->setExpectedException(NotifyException::class, 'Unable to log the notification.'); $publisher->retryNotification($destination, $message); } }