diff -u b/core/modules/migrate/src/Event/MigrateEvents.php b/core/modules/migrate/src/Event/MigrateEvents.php --- b/core/modules/migrate/src/Event/MigrateEvents.php +++ b/core/modules/migrate/src/Event/MigrateEvents.php @@ -186,7 +186,7 @@ * * This event allows modules to perform and action when the limit is reached. * The event lister method receives a - * \Drupal\migrate\Event\MigrateMemoryLimitEvent + * \Drupal\migrate\Event\MigrateMemoryLimitEvent. * * @Event * diff -u b/core/modules/migrate/src/EventSubscriber/MemoryLimitExceeded.php b/core/modules/migrate/src/EventSubscriber/MemoryLimitExceeded.php --- b/core/modules/migrate/src/EventSubscriber/MemoryLimitExceeded.php +++ b/core/modules/migrate/src/EventSubscriber/MemoryLimitExceeded.php @@ -9,6 +9,9 @@ use Drupal\migrate\MigrateMessage; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +/** + * Class MemoryLimitExceeded + */ class MemoryLimitExceeded implements EventSubscriberInterface { use StringTranslationTrait; diff -u b/core/modules/migrate/src/MemoryManager.php b/core/modules/migrate/src/MemoryManager.php --- b/core/modules/migrate/src/MemoryManager.php +++ b/core/modules/migrate/src/MemoryManager.php @@ -20,7 +20,7 @@ protected $memoryReclaimThreshold; /** - * The ratio of the memory limit at which a reclaim is triggered. + * The ratio of the memory limit at which an operation will be interrupted. * * @var float */ @@ -33,7 +33,6 @@ */ protected $memoryLimit; - /** * The event dispatcher. * @@ -43,11 +42,20 @@ /** * MemoryManager constructor. + * + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher + * The event dispatcher. + * @param int $reclaim_threshold + * The ratio of the memory limit which will trigger a failed reclaim. + * @param int $memory_threshold + * The ratio of the memory limit at which an operation will be interrupted. + * @param int $memory_limit + * The memory limit. */ - public function __construct(EventDispatcherInterface $dispatcher, $reclaim_threshold, $max_threshold, $memory_limit = NULL) { + public function __construct(EventDispatcherInterface $dispatcher, $reclaim_threshold, $memory_threshold, $memory_limit = NULL) { $this->dispatcher = $dispatcher; $this->memoryReclaimThreshold = $reclaim_threshold; - $this->memoryThreshold = $max_threshold; + $this->memoryThreshold = $memory_threshold; // Record the memory limit in bytes. if (isset($memory_limit)) { $this->memoryLimit = Bytes::toInt($memory_limit); @@ -108,6 +116,7 @@ * Returns the amount of memory used as a percentage. * * @return float|int + * The amount of memory used as a percentage. */ protected function getUsageRatio() { return $this->getUsageInBytes() / $this->getLimit(); diff -u b/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php b/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php --- b/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php +++ b/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php @@ -2,8 +2,6 @@ namespace Drupal\Tests\migrate\Unit; -use Drupal\migrate\MigrateMessageInterface; - /** * Tests the \Drupal\migrate\MigrateExecutable::memoryExceeded() method. * @@ -12,6 +10,13 @@ class MigrateExecutableMemoryExceededTest extends MigrateTestCase { /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + + /** * The mocked migration entity. * * @var \Drupal\migrate\Plugin\MigrationInterface|\PHPUnit\Framework\MockObject\MockObject @@ -54,67 +59,84 @@ protected function setUp() { parent::setUp(); $this->migration = $this->getMigration(); - - $this->executable->getMemoryManager()->setMessage($this->getMock(MigrateMessageInterface::class)); - $this->executable->getMemoryManager()->setStringTranslation($this->getStringTranslationStub()); + $this->message = $this->createMock('Drupal\migrate\MigrateMessageInterface'); + $this->eventDispatcher = $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); } /** - * Runs the actual test. + * Test memory manager * * @param string $message * The second message to assert. - * @param bool $memory_exceeded - * Whether to test the memory exceeded case. + * @param int|null $memory_limit + * (optional) The memory limit. Defaults to NULL. + * @param float $reclaim_threshold + * The ratio of the memory limit which will trigger a failed reclaim. + * @param float $memory_threshold + * The ratio of the memory limit at which an operation will be interrupted. * @param int|null $memory_usage_first * (optional) The first memory usage value. Defaults to NULL. * @param int|null $memory_usage_second * (optional) The fake amount of memory usage reported after memory reclaim. * Defaults to NULL. - * @param int|null $memory_limit - * (optional) The memory limit. Defaults to NULL. + * @param bool $memory_exceeded + * Whether to test the memory exceeded case. + * + * @dataProvider memoryExceededProvider */ - protected function runMemoryExceededTest($message, $memory_exceeded, $memory_usage_first = NULL, $memory_usage_second = NULL, $memory_limit = NULL) { - $this->executable->getMemoryManager()->setMemoryLimit($memory_limit ?: $this->memoryLimit); - $this->executable->getMemoryManager()->setMemoryUsage($memory_usage_first ?: $this->memoryLimit, $memory_usage_second ?: $this->memoryLimit); - if ($message) { - $this->executable->getMemoryManager()->getMessage()->expects($this->at(0)) - ->method('display') - ->with($this->stringContains('reclaiming memory')); - $this->executable->getMemoryManager()->getMessage()->expects($this->at(1)) - ->method('display') - ->with($this->stringContains($message)); - } - else { - $this->executable->getMemoryManager() - ->getMessage() - ->expects($this->never()) - ->method($this->anything()); - } - $result = $this->executable->getMemoryManager()->memoryExceeded(); - $this->assertEquals($memory_exceeded, $result); - } + public function testMemoryExceeded($message, $memory_limit, $reclaim_threshold, $memory_threshold, $memory_usage_first, $memory_usage_second, $memory_exceeded) { + $this->executable = new TestMigrateExecutable($this->migration, $this->message, $this->eventDispatcher, NULL); - /** - * Tests memoryExceeded method when a new batch is needed. - */ - public function testMemoryExceededNewBatch() { - // First case try reset and then start new batch. - $this->runMemoryExceededTest('starting new batch', TRUE); - } + // Get the memory and set parameters. + $memory_manager = $this->executable->getMemoryManager(); + $memory_manager->setMemoryLimit($memory_limit); + $memory_manager->setMemoryReclaimThreshold($reclaim_threshold); + $memory_manager->setMemoryThreshold($memory_threshold); + $memory_manager->setMemoryUsage($memory_usage_first ?: $this->memoryLimit, $memory_usage_second ?: $this->memoryLimit); - /** - * Tests memoryExceeded method when enough is cleared. - */ - public function testMemoryExceededClearedEnough() { - $this->runMemoryExceededTest('reclaimed enough', FALSE, $this->memoryLimit, $this->memoryLimit * 0.75); + if ($memory_usage_second) { + $memory_manager->reclaim(); + } + $result = $memory_manager->isLimitExceeded(1); + $this->assertEquals($memory_exceeded, $result); } /** - * Tests memoryExceeded when memory usage is not exceeded. + * Memory manager test data provider. */ - public function testMemoryNotExceeded() { - $this->runMemoryExceededTest('', FALSE, floor($this->memoryLimit * 0.85) - 1); + public function memoryExceededProvider() { + return [ + // Tests memoryExceeded method when a new batch is needed. + 'MemoryExceededNewBatch' => [ + 'message' => 'starting new batch', + 'memory_limit' => $this->memoryLimit, + 'reclaim_threshold' => 0.9, + 'memory_threshold' => 0.85, + 'memory_usage_first' => NULL, + 'memory_usage_second' => NULL, + 'memory_exceeded' => TRUE, + ], + // Tests memoryExceeded method when enough is cleared. + 'testMemoryExceededClearedEnough' => [ + 'message' => 'reclaimed enough', + 'memory_limit' => $this->memoryLimit, + 'reclaim_threshold' => 0.9, + 'memory_threshold' => 0.85, + 'memory_usage_first' => $this->memoryLimit, + 'memory_usage_second' => $this->memoryLimit * 0.75, + 'memory_exceeded' => FALSE, + ], + // Tests memoryExceeded when memory usage is not exceeded. + 'testMemoryNotExceeded' => [ + 'message' => 'starting new batch', + 'memory_limit' => $this->memoryLimit, + 'reclaim_threshold' => 0.9, + 'memory_threshold' => 0.85, + 'memory_usage_first' => floor($this->memoryLimit * 0.85) - 1, + 'memory_usage_second' => NULL, + 'memory_exceeded' => FALSE, + ], + ]; } } diff -u b/core/modules/migrate/tests/src/Unit/TestMigrateExecutable.php b/core/modules/migrate/tests/src/Unit/TestMigrateExecutable.php --- b/core/modules/migrate/tests/src/Unit/TestMigrateExecutable.php +++ b/core/modules/migrate/tests/src/Unit/TestMigrateExecutable.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\migrate\Unit; use Drupal\migrate\MemoryManager; +use Drupal\migrate\MemoryManagerInterface; use Drupal\migrate\MigrateExecutable; use Drupal\migrate\MigrateMessageInterface; use Drupal\migrate\Plugin\MigrationInterface; @@ -13,9 +14,23 @@ */ class TestMigrateExecutable extends MigrateExecutable { - public function __construct(MigrationInterface $migration, MigrateMessageInterface $message = NULL, EventDispatcherInterface $event_dispatcher = NULL) { + /** + * Constructs a TestMigrateExecutable and verifies and sets the memory limit. + * + * @param \Drupal\migrate\Plugin\MigrationInterface $migration + * The migration to run. + * @param \Drupal\migrate\MigrateMessageInterface $message + * (optional) The migrate message service. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * (optional) The event dispatcher. + * @param \Drupal\Migrate\MemoryManagerInterface $memory_manager + * (optional) The memory manager. + * + * @throws \Drupal\migrate\MigrateException + */ + public function __construct(MigrationInterface $migration, MigrateMessageInterface $message = NULL, EventDispatcherInterface $event_dispatcher = NULL, MemoryManagerInterface $memory_manager = NULL) { parent::__construct($migration, $message, $event_dispatcher); - $this->memoryManager = new TestMemoryManager(); + $this->memoryManager = new TestMemoryManager($this->eventDispatcher, NULL, NULL, NULL); } /** @@ -83,29 +98,23 @@ /** * {@inheritdoc} */ - protected function reclaim() { - $this->memoryUsage = $this->clearedMemoryUsage; - return $this; + public function getUsageInBytes() { + return $this->memoryUsage; } /** * {@inheritdoc} */ - protected function getUsageInBytes() { - return $this->memoryUsage; + public function isLimitExceeded($multiplier = 1) { + return parent::isLimitExceeded($multiplier); } /** - * Sets the fake memory usage. - * - * @param int $memory_usage - * The fake memory usage value. - * @param int $cleared_memory_usage - * (optional) The fake cleared memory value. Defaults to NULL. + * Reclaim memory. */ - public function setMemoryUsage($memory_usage, $cleared_memory_usage = NULL) { - $this->memoryUsage = $memory_usage; - $this->clearedMemoryUsage = $cleared_memory_usage; + public function reclaim() { + $this->memoryUsage = $this->clearedMemoryUsage; + return $this; } /** @@ -119,30 +128,36 @@ } /** - * Set the message service. + * Sets the memory threshold. * - * @param \Drupal\migrate\MigrateMessageInterface $message - * The message service. + * @param float $threshold + * The new threshold. */ - public function setMessage(MigrateMessageInterface $message) { - $this->message = $message; + public function setMemoryReclaimThreshold($threshold) { + $this->memoryReclaimThreshold = $threshold; } /** - * Get the message service. + * Sets the memory threshold. * - * @return \Drupal\migrate\MigrateMessage|\Drupal\migrate\MigrateMessageInterface - * The message. + * @param float $threshold + * The new threshold. */ - public function getMessage() { - return $this->message; + public function setMemoryThreshold($threshold) { + $this->memoryThreshold = $threshold; } /** - * {@inheritdoc} + * Sets the fake memory usage. + * + * @param int $memory_usage + * The fake memory usage value. + * @param int $cleared_memory_usage + * (optional) The fake cleared memory value. Defaults to NULL. */ - protected function formatSize($size) { - return $size; + public function setMemoryUsage($memory_usage, $cleared_memory_usage = NULL) { + $this->memoryUsage = $memory_usage; + $this->clearedMemoryUsage = $cleared_memory_usage; } } only in patch2: unchanged: --- a/core/modules/migrate/tests/src/Unit/MigrateExecutableTest.php +++ b/core/modules/migrate/tests/src/Unit/MigrateExecutableTest.php @@ -53,7 +53,8 @@ protected function setUp() { $this->migration = $this->getMigration(); $this->message = $this->createMock('Drupal\migrate\MigrateMessageInterface'); $event_dispatcher = $this->createMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); - $this->executable = new TestMigrateExecutable($this->migration, $this->message, $event_dispatcher); + $memory_manager = $this->createMock('Drupal\migrate\MemoryManagerInterface'); + $this->executable = new TestMigrateExecutable($this->migration, $this->message, $event_dispatcher, $memory_manager); $this->executable->setStringTranslation($this->getStringTranslationStub()); }