diff --git a/src/FeedImportHandler.php b/src/FeedImportHandler.php index 671648dd..43b161cf 100644 --- a/src/FeedImportHandler.php +++ b/src/FeedImportHandler.php @@ -2,6 +2,7 @@ namespace Drupal\feeds; +use Drupal\Core\File\FileSystemInterface; use Drupal\feeds\Exception\LockException; use Drupal\feeds\Result\RawFetcherResult; @@ -20,8 +21,8 @@ class FeedImportHandler extends FeedHandlerBase { * In case of an error. */ public function import(FeedInterface $feed) { - $executable = \Drupal::service('class_resolver')->getInstanceFromDefinition(FeedsExecutable::class); - $executable->processItem($feed, FeedsExecutable::BEGIN); + $this->getExecutable(FeedsExecutable::class) + ->processItem($feed, FeedsExecutable::BEGIN); } /** @@ -34,8 +35,8 @@ class FeedImportHandler extends FeedHandlerBase { * Thrown if a feed is locked. */ public function startBatchImport(FeedInterface $feed) { - $executable = \Drupal::service('class_resolver')->getInstanceFromDefinition(FeedsBatchExecutable::class); - $executable->processItem($feed, FeedsBatchExecutable::BEGIN); + $this->getExecutable(FeedsBatchExecutable::class) + ->processItem($feed, FeedsBatchExecutable::BEGIN); } /** @@ -53,11 +54,11 @@ class FeedImportHandler extends FeedHandlerBase { throw new LockException($this->t('The feed @id / @fid is locked.', $args)); } - $executable = \Drupal::service('class_resolver')->getInstanceFromDefinition(FeedsQueueExecutable::class); - $executable->processItem($feed, FeedsQueueExecutable::BEGIN); + $this->getExecutable(FeedsQueueExecutable::class) + ->processItem($feed, FeedsQueueExecutable::BEGIN); // Add timestamp to avoid queueing item more than once. - $feed->setQueuedTime(\Drupal::time()->getRequestTime()); + $feed->setQueuedTime($this->getRequestTime()); $feed->save(); } @@ -68,15 +69,40 @@ class FeedImportHandler extends FeedHandlerBase { * The feed receiving the push. * @param string $payload * The feed contents. + * @param \Drupal\Core\File\FileSystemInterface $file_system + * (optional) The file system service. */ - public function pushImport(FeedInterface $feed, $payload) { + public function pushImport(FeedInterface $feed, $payload, FileSystemInterface $file_system = NULL) { $feed->lock(); - $fetcher_result = new RawFetcherResult($payload); + $fetcher_result = new RawFetcherResult($payload, $file_system); - $executable = \Drupal::service('class_resolver')->getInstanceFromDefinition(FeedsQueueExecutable::class); - $executable->processItem($feed, FeedsQueueExecutable::PARSE, [ + $this->getExecutable(FeedsQueueExecutable::class) + ->processItem($feed, FeedsQueueExecutable::PARSE, [ 'fetcher_result' => $fetcher_result, ]); } + /** + * Returns the timestamp for the current request. + * + * @return int + * A Unix timestamp. + */ + protected function getRequestTime() { + return \Drupal::time()->getRequestTime(); + } + + /** + * Returns the executable. + * + * @param string $class + * The class to load. + * + * @return \Drupal\feeds\FeedsExecutableInterface + * A feeds executable. + */ + protected function getExecutable($class) { + return \Drupal::service('class_resolver')->getInstanceFromDefinition($class); + } + } diff --git a/src/FeedsDirectBatch.php b/src/FeedsDirectBatch.php index 1361c55f..f082a048 100644 --- a/src/FeedsDirectBatch.php +++ b/src/FeedsDirectBatch.php @@ -2,8 +2,6 @@ namespace Drupal\feeds; -use Drupal\Core\StringTranslation\StringTranslationTrait; - /** * A batch task to be executed directly. */ diff --git a/src/Plugin/QueueWorker/FeedRefresh.php b/src/Plugin/QueueWorker/FeedRefresh.php index 95bdea31..805ca8cc 100644 --- a/src/Plugin/QueueWorker/FeedRefresh.php +++ b/src/Plugin/QueueWorker/FeedRefresh.php @@ -33,8 +33,17 @@ class FeedRefresh extends FeedQueueWorkerBase { return; } - $executable = \Drupal::service('class_resolver')->getInstanceFromDefinition(FeedsQueueExecutable::class); - $executable->processItem($feed, $stage, $params); + $this->getExecutable()->processItem($feed, $stage, $params); + } + + /** + * Returns Feeds executable. + * + * @return \Drupal\feed\FeedsExecutableInterface + * A feeds executable. + */ + protected function getExecutable() { + return \Drupal::service('class_resolver')->getInstanceFromDefinition(FeedsQueueExecutable::class); } /** diff --git a/src/Result/RawFetcherResult.php b/src/Result/RawFetcherResult.php index 9d03eea0..ae537b43 100644 --- a/src/Result/RawFetcherResult.php +++ b/src/Result/RawFetcherResult.php @@ -31,7 +31,7 @@ class RawFetcherResult extends FetcherResult { * @param string $raw * The raw result string. * @param \Drupal\Core\File\FileSystemInterface $file_system - * The file system service. + * (optional) The file system service. */ public function __construct($raw, FileSystemInterface $file_system = NULL) { $this->raw = $raw; diff --git a/tests/src/Functional/FieldValidationTest.php b/tests/src/Functional/FieldValidationTest.php index 04bdb4f9..860a2479 100644 --- a/tests/src/Functional/FieldValidationTest.php +++ b/tests/src/Functional/FieldValidationTest.php @@ -126,6 +126,7 @@ class FieldValidationTest extends FeedsBrowserTestBase { // Create an user that can trigger the import. $account = $this->drupalCreateUser([ + 'view my_feed_type feeds', 'import my_feed_type feeds', ]); $this->drupalLogin($account); @@ -135,7 +136,7 @@ class FieldValidationTest extends FeedsBrowserTestBase { // Assert that 2 nodes have been created. $this->assertNodeCount(2); - $this->assertSession()->pageTextContains('Created 2 nodes'); + $this->assertSession()->pageTextContains('Created 2 Articles'); } /** diff --git a/tests/src/Unit/FeedImportHandlerTest.php b/tests/src/Unit/FeedImportHandlerTest.php index a4b37302..a1c0c7b4 100644 --- a/tests/src/Unit/FeedImportHandlerTest.php +++ b/tests/src/Unit/FeedImportHandlerTest.php @@ -2,12 +2,14 @@ namespace Drupal\Tests\feeds\Unit; +use Drupal\Core\File\FileSystemInterface; use Drupal\feeds\Event\FeedsEvents; use Drupal\feeds\Event\FetchEvent; use Drupal\feeds\Event\ParseEvent; use Drupal\feeds\Event\ProcessEvent; use Drupal\feeds\FeedInterface; use Drupal\feeds\FeedImportHandler; +use Drupal\feeds\FeedsExecutableInterface; use Drupal\feeds\Feeds\Item\ItemInterface; use Drupal\feeds\Result\FetcherResultInterface; use Drupal\feeds\Result\ParserResultInterface; @@ -33,6 +35,13 @@ class FeedImportHandlerTest extends FeedsUnitTestCase { */ protected $feed; + /** + * The handler to test. + * + * @var \Drupal\feeds\FeedImportHandler + */ + protected $handler; + /** * {@inheritdoc} */ @@ -40,10 +49,16 @@ class FeedImportHandlerTest extends FeedsUnitTestCase { parent::setUp(); $this->dispatcher = new EventDispatcher(); - $this->handler = new FeedImportHandler($this->dispatcher); + $this->handler = $this->getMockBuilder(FeedImportHandler::class) + ->setConstructorArgs([$this->dispatcher]) + ->setMethods(['getRequestTime', 'getExecutable']) + ->getMock(); $this->handler->setStringTranslation($this->getStringTranslationStub()); + $this->handler->expects($this->any()) + ->method('getRequestTime') + ->willReturn(time()); - $this->feed = $this->getMock(FeedInterface::class); + $this->feed = $this->createMock(FeedInterface::class); $this->feed->expects($this->any()) ->method('id') ->will($this->returnValue(10)); @@ -52,55 +67,56 @@ class FeedImportHandlerTest extends FeedsUnitTestCase { ->will($this->returnValue('test_feed')); } + /** + * @covers ::import + */ + public function testImport() { + $this->handler->expects($this->once()) + ->method('getExecutable') + ->willReturn($this->createMock(FeedsExecutableInterface::class)); + + $this->handler->import($this->feed); + } + /** * @covers ::startBatchImport */ public function testStartBatchImport() { - $this->feed->expects($this->once()) - ->method('lock') - ->will($this->returnValue($this->feed)); + $this->handler->expects($this->once()) + ->method('getExecutable') + ->willReturn($this->createMock(FeedsExecutableInterface::class)); $this->handler->startBatchImport($this->feed); } /** - * @covers ::batchFetch - * @covers ::batchParse - * @covers ::batchProcess - * @covers ::doFetch - * @covers ::doParse - * @covers ::doProcess + * @covers ::startCronImport */ - public function testBatch() { - $this->addDefaultEventListeners(); + public function testStartCronImport() { + $this->feed->expects($this->once()) + ->method('isLocked') + ->will($this->returnValue(FALSE)); - $this->feed->expects($this->exactly(3)) - ->method('saveStates'); + $this->handler->expects($this->once()) + ->method('getExecutable') + ->willReturn($this->createMock(FeedsExecutableInterface::class)); - $this->handler->batchFetch($this->feed); - $this->handler->batchParse($this->feed); - $this->handler->batchProcess($this->feed, $this->getMock(ItemInterface::class)); + $this->handler->startCronImport($this->feed); } /** - * Adds default listeners to event dispatcher. + * @covers ::pushImport */ - protected function addDefaultEventListeners() { - $fetcher_result = $this->getMock(FetcherResultInterface::class); - $parser_result = $this->getMock(ParserResultInterface::class); - - $this->dispatcher->addListener(FeedsEvents::FETCH, function (FetchEvent $event) use ($fetcher_result) { - $event->setFetcherResult($fetcher_result); - }); - - $this->dispatcher->addListener(FeedsEvents::PARSE, function (ParseEvent $event) use ($fetcher_result, $parser_result) { - $this->assertSame($event->getFetcherResult(), $fetcher_result); - $event->setParserResult($parser_result); - }); - - $this->dispatcher->addListener(FeedsEvents::PROCESS, function (ProcessEvent $event) use ($parser_result) { - $this->assertInstanceOf(ItemInterface::class, $event->getItem()); - }); + public function testPushImport() { + $this->handler->expects($this->once()) + ->method('getExecutable') + ->willReturn($this->createMock(FeedsExecutableInterface::class)); + $this->feed->expects($this->once()) + ->method('lock') + ->will($this->returnValue($this->feed)); + + $file = $this->resourcesPath() . '/csv/example.csv'; + $this->handler->pushImport($this->feed, file_get_contents($file), $this->createMock(FileSystemInterface::class)); } } diff --git a/tests/src/Unit/FeedsExecutableTest.php b/tests/src/Unit/FeedsExecutableTest.php new file mode 100644 index 00000000..bf4a6e09 --- /dev/null +++ b/tests/src/Unit/FeedsExecutableTest.php @@ -0,0 +1,108 @@ +createMock(EntityTypeManagerInterface::class); + $this->dispatcher = new EventDispatcher(); + $messenger = $this->createMock(MessengerInterface::class); + + $this->executable = new FeedsExecutable($entity_type_manager, $this->dispatcher, $this->getMockedAccountSwitcher(), $messenger); + $this->executable->setStringTranslation($this->getStringTranslationStub()); + + $this->feed = $this->createMock(FeedInterface::class); + $this->feed->expects($this->any()) + ->method('id') + ->will($this->returnValue(10)); + $this->feed->expects($this->any()) + ->method('bundle') + ->will($this->returnValue('test_feed')); + } + + /** + * @covers ::doFetch + * @covers ::doParse + * @covers ::doProcess + */ + public function testImport() { + $this->addDefaultEventListeners(); + + $this->feed->expects($this->once()) + ->method('progressParsing') + ->willReturn(StateInterface::BATCH_COMPLETE); + $this->feed->expects($this->once()) + ->method('progressFetching') + ->willReturn(StateInterface::BATCH_COMPLETE); + $this->feed->expects($this->once()) + ->method('progressCleaning') + ->willReturn(StateInterface::BATCH_COMPLETE); + + $this->feed->expects($this->exactly(3)) + ->method('saveStates'); + + $this->executable->processItem($this->feed, FeedsExecutable::BEGIN); + } + + /** + * Adds default listeners to event dispatcher. + */ + protected function addDefaultEventListeners() { + $fetcher_result = $this->createMock(FetcherResultInterface::class); + $parser_result = new ParserResult(); + $parser_result->addItem($this->createMock(ItemInterface::class)); + + $this->dispatcher->addListener(FeedsEvents::FETCH, function (FetchEvent $event) use ($fetcher_result) { + $event->setFetcherResult($fetcher_result); + }); + + $this->dispatcher->addListener(FeedsEvents::PARSE, function (ParseEvent $event) use ($fetcher_result, $parser_result) { + $this->assertSame($event->getFetcherResult(), $fetcher_result); + $event->setParserResult($parser_result); + }); + + $this->dispatcher->addListener(FeedsEvents::PROCESS, function (ProcessEvent $event) use ($parser_result) { + $this->assertInstanceOf(ItemInterface::class, $event->getItem()); + }); + } + +} diff --git a/tests/src/Unit/Plugin/QueueWorker/FeedRefreshTest.php b/tests/src/Unit/Plugin/QueueWorker/FeedRefreshTest.php index 39a949ed..21b8e078 100644 --- a/tests/src/Unit/Plugin/QueueWorker/FeedRefreshTest.php +++ b/tests/src/Unit/Plugin/QueueWorker/FeedRefreshTest.php @@ -3,8 +3,11 @@ namespace Drupal\Tests\feeds\Unit\Plugin\QueueWorker; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Queue\QueueFactory; use Drupal\Core\Queue\QueueInterface; +use Drupal\feeds\FeedsExecutableInterface; +use Drupal\feeds\FeedsQueueExecutable; use Drupal\feeds\Event\FeedsEvents; use Drupal\feeds\Exception\LockException; use Drupal\feeds\Feeds\Item\DynamicItem; @@ -56,8 +59,12 @@ class FeedRefreshTest extends FeedsUnitTestCase { ->will($this->returnValue($this->getMock(QueueInterface::class))); $entity_type_manager = $this->getMock(EntityTypeManagerInterface::class); + $messenger = $this->getMock(MessengerInterface::class); - $this->plugin = $this->getMock(FeedRefresh::class, ['feedExists'], [ + $executable = new FeedsQueueExecutable($entity_type_manager, $this->dispatcher, $this->getMockedAccountSwitcher(), $messenger, $queue_factory); + $executable->setStringTranslation($this->getStringTranslationStub()); + + $this->plugin = $this->getMock(FeedRefresh::class, ['feedExists', 'getExecutable'], [ [], 'feeds_feed_refresh', [], @@ -69,6 +76,9 @@ class FeedRefreshTest extends FeedsUnitTestCase { $this->plugin->expects($this->any()) ->method('feedExists') ->will($this->returnValue(TRUE)); + $this->plugin->expects($this->any()) + ->method('getExecutable') + ->will($this->returnValue($executable)); $this->feed = $this->getMockFeed(); $this->feed->expects($this->any()) @@ -82,7 +92,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { */ public function testBeginStage() { $this->plugin->processItem(NULL); - $this->plugin->processItem([$this->feed, FeedRefresh::BEGIN, []]); + $this->plugin->processItem([$this->feed, FeedsExecutableInterface::BEGIN, []]); } /** @@ -92,29 +102,19 @@ class FeedRefreshTest extends FeedsUnitTestCase { $this->feed->expects($this->once()) ->method('lock') ->will($this->throwException(new LockException())); - $this->plugin->processItem([$this->feed, FeedRefresh::BEGIN, []]); - } - - /** - * Tests resuming an import. - * - * @todo more testing? - */ - public function testResumeStage() { - $this->plugin->processItem([$this->feed, FeedRefresh::RESUME, []]); + $this->plugin->processItem([$this->feed, FeedsExecutableInterface::BEGIN, []]); } /** * Tests that a fetch event is dispatched when initiating an import. - * - * @expectedException \RuntimeException */ public function testExceptionOnFetchEvent() { $this->dispatcher->addListener(FeedsEvents::FETCH, function ($parse_event) { throw new \RuntimeException(); }); - $this->plugin->processItem([$this->feed, FeedRefresh::BEGIN, []]); + $this->setExpectedException(\RuntimeException::class); + $this->plugin->processItem([$this->feed, FeedsExecutableInterface::FETCH, []]); } /** @@ -131,7 +131,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { $this->plugin->processItem([ $this->feed, - FeedRefresh::PARSE, [ + FeedsExecutableInterface::PARSE, [ 'fetcher_result' => $fetcher_result, ], ]); @@ -152,7 +152,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { $this->plugin->processItem([ $this->feed, - FeedRefresh::PARSE, [ + FeedsExecutableInterface::PARSE, [ 'fetcher_result' => new FetcherResult(''), ], ]); @@ -164,7 +164,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { public function testProcessStage() { $this->plugin->processItem([ $this->feed, - FeedRefresh::PROCESS, [ + FeedsExecutableInterface::PROCESS, [ 'item' => new DynamicItem(), ], ]); @@ -185,7 +185,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { $this->plugin->processItem([ $this->feed, - FeedRefresh::PROCESS, [ + FeedsExecutableInterface::PROCESS, [ 'item' => new DynamicItem(), ], ]); @@ -197,7 +197,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { public function testFinalPass() { $this->plugin->processItem([ $this->feed, - FeedRefresh::FINISH, [ + FeedsExecutableInterface::FINISH, [ 'fetcher_result' => new FetcherResult(''), ], ]); @@ -208,7 +208,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { $this->plugin->processItem([ $this->feed, - FeedRefresh::FINISH, [ + FeedsExecutableInterface::FINISH, [ 'fetcher_result' => new FetcherResult(''), ], ]); @@ -217,7 +217,7 @@ class FeedRefreshTest extends FeedsUnitTestCase { ->will($this->returnValue(StateInterface::BATCH_COMPLETE)); $this->plugin->processItem([ $this->feed, - FeedRefresh::FINISH, [ + FeedsExecutableInterface::FINISH, [ 'fetcher_result' => new FetcherResult(''), ], ]);