function CronSuspendQueueDelayTest::testSuspendQueueOrder

Same name in other branches
  1. 10 core/tests/Drupal/Tests/Core/Cron/CronSuspendQueueDelayTest.php \Drupal\Tests\Core\Cron\CronSuspendQueueDelayTest::testSuspendQueueOrder()

Tests queues are executed in order.

If multiple queues are delayed, they must execute in order of time.

File

core/tests/Drupal/Tests/Core/Cron/CronSuspendQueueDelayTest.php, line 308

Class

CronSuspendQueueDelayTest
Test Cron handling of suspended queues with a delay.

Namespace

Drupal\Tests\Core\Cron

Code

public function testSuspendQueueOrder() : void {
    [
        'queueFactory' => $queueFactory,
        'queueManager' => $queueManager,
        'time' => $time,
    ] = $this->cronConstructorArguments;
    $cron = $this->getMockBuilder(Cron::class)
        ->onlyMethods([
        'usleep',
    ])
        ->setConstructorArgs($this->cronConstructorArguments)
        ->getMock();
    $cron->expects($this->any())
        ->method('usleep');
    $queueManager->expects($this->once())
        ->method('getDefinitions')
        ->willReturn([
        'test_worker_a' => [
            'id' => 'test_worker_a',
            'cron' => [
                'time' => 300,
            ],
        ],
        'test_worker_b' => [
            'id' => 'test_worker_b',
            'cron' => [
                'time' => 300,
            ],
        ],
        'test_worker_c' => [
            'id' => 'test_worker_c',
            'cron' => [
                'time' => 300,
            ],
        ],
        'test_worker_d' => [
            'id' => 'test_worker_d',
            'cron' => [
                'time' => 300,
            ],
        ],
    ]);
    $queueA = $this->createMock(QueueInterface::class);
    $queueB = $this->createMock(QueueInterface::class);
    $queueC = $this->createMock(QueueInterface::class);
    $queueD = $this->createMock(QueueInterface::class);
    $queueFactory->expects($this->exactly(4))
        ->method('get')
        ->willReturnMap([
        [
            'test_worker_a',
            FALSE,
            $queueA,
        ],
        [
            'test_worker_b',
            FALSE,
            $queueB,
        ],
        [
            'test_worker_c',
            FALSE,
            $queueC,
        ],
        [
            'test_worker_d',
            FALSE,
            $queueD,
        ],
    ]);
    $queueA->expects($this->any())
        ->method('claimItem')
        ->willReturnOnConsecutiveCalls((object) [
        'data' => 'test_data_from_queue_a',
    ], FALSE);
    $queueB->expects($this->any())
        ->method('claimItem')
        ->willReturnOnConsecutiveCalls((object) [
        'data' => 'test_data_from_queue_b',
    ], (object) [
        'data' => 'test_data_from_queue_b',
    ], FALSE);
    $queueC->expects($this->any())
        ->method('claimItem')
        ->willReturnOnConsecutiveCalls((object) [
        'data' => 'test_data_from_queue_c',
    ], (object) [
        'data' => 'test_data_from_queue_c',
    ], FALSE);
    $queueD->expects($this->any())
        ->method('claimItem')
        ->willReturnOnConsecutiveCalls((object) [
        'data' => 'test_data_from_queue_d',
    ], FALSE);
    // Recycle the same worker for all queues to test order sanely:
    $queueManager->expects($this->any())
        ->method('createInstance')
        ->willReturnMap([
        [
            'test_worker_a',
            [],
            $this->workerA,
        ],
        [
            'test_worker_b',
            [],
            $this->workerA,
        ],
        [
            'test_worker_c',
            [],
            $this->workerA,
        ],
        [
            'test_worker_d',
            [],
            $this->workerA,
        ],
    ]);
    $queues = [
        // All queues are executed in sequence of definition:
'test_data_from_queue_a',
        'test_data_from_queue_b',
        'test_data_from_queue_c',
        'test_data_from_queue_d',
        // Queue C is executed again, and before queue B.
'test_data_from_queue_c',
        // Queue B is executed again, after queue C since its delay was longer.
'test_data_from_queue_b',
    ];
    $this->workerA
        ->expects($this->exactly(count($queues)))
        ->method('processItem')
        ->with($this->callback(function ($queue) use (&$queues) : bool {
        return array_shift($queues) === $queue;
    }))
        ->willReturnOnConsecutiveCalls(NULL, $this->throwException(new SuspendQueueException('', 0, NULL, 16.0)), $this->throwException(new SuspendQueueException('', 0, NULL, 8.0)), NULL, NULL, NULL);
    $currentTime = 60;
    $time->expects($this->any())
        ->method('getCurrentTime')
        ->willReturnCallback(function () use (&$currentTime) : int {
        return (int) $currentTime;
    });
    $time->expects($this->any())
        ->method('getCurrentMicroTime')
        ->willReturnCallback(function () use (&$currentTime) : float {
        return (double) $currentTime;
    });
    $delays = [
        // Expect to wait for 8 seconds, then accelerate time by 4 seconds.
4,
        8000000,
        // SuspendQueueException requests to delay by 16 seconds, but 4 seconds
        // have passed above, so there are just 12 seconds remaining:
0,
        12000000,
    ];
    $cron->expects($this->exactly(count($delays) / 2))
        ->method('usleep')
        ->with($this->callback(function (int $delay) use (&$currentTime, &$delays) : bool {
        $currentTime += array_shift($delays);
        return array_shift($delays) === $delay;
    }));
    $cron->run();
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.